Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад] [Содержание] [Дальше]

Создание Web-приложений: Практическое руководство

© Александр Фролов, Григорий Фролов
М.: Русская Редакция, 2001, 1040 стр.

14. Проект Интернет-магазина

14. Проект Интернет-магазина.. 1

Структура Интернет-магазина.. 2

Административное приложение Back-офиса. 3

Структура базы данных Интернет-магазина. 3

Реализация приложения Back-офиса. 5

Приложение Front-офиса. 6

База данных Интернет-магазина.. 8

Создание базы данных. 8

Подготовка таблиц. 8

Таблица managers. 9

Таблица clients. 10

Таблица books. 12

Таблица orders. 13

Подготовка хранимых процедур. 14

Создание источника данных. 15

Настройка сервера Web.. 19

Виртуальный каталог приложения покупателя BookShopClient 20

Виртуальный каталог административного приложения BookShop. 20

Приложение покупателя.. 22

Файл global.asa. 27

Страницы входа и начальной регистрации. 28

Вход зарегистрированных посетителей. 28

Обработка ошибок. 30

Хранимая процедура ClientLogin. 31

Определение фреймов главной страницы.. 32

Страница меню команд. 33

Страница просмотра списка книг. 33

Добавление книги в корзину. 35

Страница просмотра содержимого корзины.. 35

Удаление книги из корзины.. 38

Административное приложение Back-офиса.. 39

Файл global.asa. 47

Страницы входа. 47

Главная страница. 48

Страница меню команд. 49

Страница с сообщением о подключении. 49

Страницы управления персоналом.. 50

Просмотр списка сотрудников. 50

Создание новой записи. 51

Удаление учетной записи сотрудника. 53

Редактирование записи сотрудника. 54

Редактирование списка книг. 56

Просмотр списка книг. 56

Добавление новой книги. 57

Удаление книги. 58

Редактирование описания книги. 59

Работа с записями покупателей. 62

Форма поиска покупателей. 62

Просмотр списка зарегистрированных покупателей. 64

Удаление записи покупателя. 67

Просмотр содержимого корзины покупателя. 70

Редактирование регистрационных данных покупателя. 71

 

 

После краткого предварительного знакомства с ADO мы предлагаем Вам выполнить практическую реализацию проекта Интернет-магазина, предназначенного для продажи книг. Под нашим руководством Вам предлагается создать базу данных магазина и набор страниц ASP, реализующих приложения покупателей и администрации магазина.

Процедуры, описанные в этом разделе, пригодятся Вам и при создании других приложений ASP с базами данных, даже если они не имеют никакого отношения к Интернет-магазинам.

Попутно при изложении материала этой главы мы будем рассказывать о реализации тех или иных компонентов реально действующего книжного Интернет-магазина http://www.itbook.ru, созданного нами по заказу издательства компьютерной литературы «Русская Редакция». Более подробно эти проекты описаны в следующей главе.

Рис. 14-1. Книжный Интернет-магазин http://www.itbook.ru

Структура Интернет-магазина

Наш Интернет-магазин будет предназначен для продажи книг, хотя положенные в его основу принципы можно применять для продажи практически любых товаров. Он будет состоять из двух самостоятельных, но, тем не менее, тесно связанных между собой Web-приложений:

·         административное Web-приложение Back-офис;

·         Web-приложение для посетителей магазина Front-офис

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

Что же касается приложения Fron-офис, то именно оно используется посетителями для просмотра информации о товарах (в нашем случае о книгах) и совершения покупок.

Административное приложение Back-офиса

Рассказ о структуре Интернет-магазина мы начнем именно с административного приложения (рис. 14-2), благодаря которому формируется информационная база данных магазина и обеспечивается его функционирование.

Рис. 14-2. Back-офис Интернет-магазина http://www.itbook.ru

Но, прежде всего, ответим на вопрос, который, возможно, у Вас возник: почему административное приложение называется Back-офисом?

Вовсе не потому, что оно создано на базе системы Microsoft Back Office, как это можно было бы подумать, а потому, что его работа, невидимая для покупателей, остается за сценой Интернет-магазина.

Back-офис предназначен для наполнения электронных каталогов, витрин и ленты новостей, обработки заказов и печати счетов, управление учетными записями сотрудников и посетителей магазина, получения и обработка статистической информации и т.д.

Структура базы данных Интернет-магазина

Ядром Интернет-магазина служит база данных. В ней хранится вся информация о товарах, заказах, клиентах и другие необходимые данные. И административное приложение, и приложение Front-офиса, с которым работают посетители магазина, обращаются к одной и той же базе данных (хотя, конечно, эти приложения выполняют над базой данных не одинаковые операции).

Чтобы обеспечить надежную работу магазина, необходимо использовать промышленные версии СУБД с обработкой транзакций. При реализации Интернет-магазина http://www.itbook.ru мы воспользовались СУБД Microsoft SQL Server версии 7.0 с пакетом обновлений Service Pack 2, неплохо зарекомендовавшей себя как с точки зрения надежности, так и с точки зрения производительности.

Если Вас интересует недорогая СУБД, то можно использовать такую известную систему, как Inprise Interbase. Эту СУБД можно бесплатно загрузить из Интернета и бесплатно использовать, так как она поставляется с исходными текстами и публичной лицензией GPL. Для непосвященных скажем, что лицензия GPL не требует отчислений за использование программы, хотя и накладывает некоторые ограничения на ее распространение (например, Вы не можете продавать программы с лицензией GPL).

База данных Интернет-магазина http://www.itbook.ru хранит следующую информацию (рис. 14-3):

·         идентификаторы и пароли сотрудников магазина;

·         регистрационную информацию посетителей магазина, пожелавших зарегистрироваться;

·         сведения о продаваемых книгах (название, автор, издательство, номер ISBN, краткая и полная аннотация, изображения обложки, примеры глав, стоимость, уровень читателя, на который ориентирована данная книга, оценки и отзывы читателей и т.д.);

·         сведения об издательствах;

·         каталог и список серий книг;

·         списки книг, имеющихся в продаже и выставленных на главную витрину магазина (эта витрина находится на главной странице магазина);

·         сообщения ленты новостей;

·         заказы, сделанные посетителями;

·         обработанные заказы;

·         информацию о тарифах и тарифных зонах, используемую для вычисления стоимости доставки книг

Рис. 14-3. Таблицы базы даных Интернет-магазина http://www.itbook.ru

Перечисленная выше информация используется для наполнения страниц Front-офиса Интернет-магазина, доступных посетителям. Поэтому для того чтобы сделать какие-либо изменения на витринах магазина, достаточно отредактировать соответствующие таблицы базы данных.

Реализация приложения Back-офиса

Для реализации приложения Back-офиса теоретически можно использовать любую известную технологию, ориентированную на клиент-серверные системы, а также многоуровневые технологии.

Например, если компьютер с базой данных Интернет-магазина подключен к локальной сети компании, занимающейся сопровождением и обслуживанием магазина, ничто не мешает Вам создать административное приложение с помощью таких средств, как Inprise Delphi, Microsoft Access или Microsoft Visual Basic.

Однако для повышения скорости работы компьютер Интернет-магазина, содержащий помимо СУБД еще и Web-сервер, обычно располагают на площадке провайдера, подключив его к Интернету высокоскоростным каналом связи. Такой компьютер обычно защищают от хакеров с помощью межсетевого экрана (известного под названиями «брандмауэр» и firewall).

Чтобы не возникало проблем с доступом к базе данных через межсетевой экран, лучше всего управлять работой магазина через Интернет с использованием обычного браузера. Такое управление можно осуществлять из любого места — из дома, офиса или гостиницы. Лишь бы была телефонная линия, компьютер и модем. Опять же, не возникает никаких проблем с установкой и настройкой рабочих станций для сотрудников магазина. Для этих станций вполне подойдет операционная система Microsoft Windows любой современной версии со встроенным в нее браузером Microsoft Internet Explorer.

Приложение Back-офиса в Интернет-магазине http://www.itbook.ru создано с применением технологии активных серверных страниц ASP. В дополнение к стандартным серверным элементам управления ActiveX, входящим в комплект IIS, для этого магазина мы разработали еще несколько:

·         MTASend — для отправки электронной почты через протокол SMTP;

·         CyrCoder — для перекодирования текстовых строк из Windows-1251 в КОИ-8;

·         RusMoney — для преобразования числа в сумму прописью (это нужно для автоматической выписки счета)

Кроме того, было разработано еще несколько модулей:

·         расширение ISAPI, предназначенное для удаленной загрузки файлов изображений обложек и образцов глав в каталоги сервера Web через браузер;

·         сценарий JavaScript, работающий в пакетном режиме под управлением Windows Scripting Host для рассылки новостей магазина по электронной почте среди тех зарегистрированных посетителей магазина, кто пожелал получать такую почту;

·         пакетный сценарий JavaScript для статистической обработки информации о покупках, сделанных посетителями магазина.

Дополнительно разработанные элементы управления ActiveX вызываются непосредственно из сценариев JavaScript, расположенных на страницах ASP, а также из пакетных сценариев, работающих под управлением Windows Scripting Host. Заметим, что для запуска пакетных сценариев, а также процедур резервного копирования базы данных мы использовали планировщик заданий, входящий в состав сервера Microsoft SQL Server версии 7.0.

Приложение Front-офиса

Как мы уже говорили, приложение Front-офиса — это то, с чем имеют дело посетители магазина. В книжном Интернет-магазине http://www.itbook.ru это приложение создано с применением тех же самых технологий, что и приложение Back-офиса, а именно страниц ASP и серверных элементов управления ActiveX. Что же касается расширений ISAPI и пакетных сценариев JavaScript, то в нашем приложении Front-офиса они не используются.

Фактически Front-офис Интернет-магазина http://www.itbook.ru состоит из нескольких компонентов, объединенных в рамках одного узла Web:

·         древовидного каталога книг (рис. 14-4), предназначенного для поиска книг по тематическим рубрикам (таким как базы данных, программирование, Web-дизайн и т.д.);

·         каталога серий книг;

·         небольшой витрины новых и наиболее популярных книг, размещенной на главной странице магазина;

·         поисковой системе (рис. 14-5), с помощью которой посетители могут найти нужные им книги по названию, ключевым словам, встречающимся в названии и аннотации, по фамилии автора, по номеру ISBN, по уровню подготовленности читателя, необходимой для работы с книгой, по названию издательства, и другим критериям. В частности, поисковая система поможет посетителям найти перевод оригинальной книги по ее названию, номеру ISBN и другим атрибутам;

·         ленты новостей, содержащей сообщения о появлении в продаже новых книг или о других событиях, связанных с работой магазина;

·         системе регистрации посетителей магазина, позволяющей получить статус привилегированного покупателя, а также подписаться на получение новостей магазина по электронной почте;

·         электронной корзины, предназначенной для хранения книг, отобранных посетителями для покупки;

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

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

·         модуля отправки отзывов о работе Интернет-магазина по электронной почте без использования специальной почтовой программы

Рис. 14-4. Рубрика Операционные системы

Рис. 14-5. Страница расширенного поиска книг

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

База данных Интернет-магазина

Далее в этой главе мы расскажем о реализации отдельных подсистем Интернет-магазина на небольшом учебном примере (полная реализация магазина слишком объемна, чтобы ее можно было привести в нашей книге). Попутно мы будем делать замечания относительно тех или иных подсистем реального магазина http://www.itbook.ru.

Вначале мы расскажем о создании базы данных, хранящей сведения о товарах, а затем займемся созданием приложений Web для Back-офиса и Front-офиса.

Создание базы данных

Итак, прежде чем приступить к изучению страниц ASP нашего Интернет-магазина нам нужно создать базу данных. Мы предполагаем, что Вы уже установили Microsoft SQL Server 2000 или Microsoft SQL Server 2000 версии 7.0, а также пакет обновлений Service Pack 2 для SQL Server 7.0 (или боле новый).

Сначала мы создадим базу данных и все необходимые таблицы, затем подготовим хранимые процедуры и установим права доступа к ним.

Подготовка таблиц

Запустите приложение SQL Server Enterprise Manager и откройте сервер базы данных. Затем выберите из меню Action строку New Database. На экране появится диалоговая панель Database Properties, показанная на рис. 14-6.

Рис. 14-6. Создание базы данных

Здесь на вкладке General в поле Name введите имя базы данных, которое мы будем использовать в нашем проекте — BookStore. Щелкнув кнопку с многоточием, расположенную в поле Location, выберите путь для размещения файла базы данных.

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

По умолчанию при создании новой базы данных на этой вкладке отмечается переключатель Automatically grow file, поэтому по мере добавления в таблицы базы данных новых записей размер файла базы данных будет увеличиваться. Величина прироста может быть указана либо в мегабайтах, либо в процентах. Включив переключатель Restrict filegrowth в поле Maximum file size, вы можете ограничить рост файла базы данных.

Вкладка Transaction Log позволяет указать размер, прирост и ограничение для файла транзакций. О том, как правильно выбирать начальные параметры при создании базы данных, Вы можете узнать в деталях из документации SQL Server.

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

Таблица managers

Эта таблица содержит информацию о персонале Интернет-магазина, управляющего его работой через Интернет с помощью специального административного приложения. Назначение полей таблицы managers объясняется в табл. 14-6.

Таблица 14-6. Поля таблицы managers

Поле

Тип

Описание

ManagerID

Int

Ключевое поле с атрибутом IDENTITY однозначно идентифицирует запись в таблице managers

Name

varchar(50)

Имя сотрудника, используется в качестве идентификатора при подключении к административному приложению Интернет-магазина

Password

varchar(50)

Пароль сотрудника

LastLogin

datetime

Время, когда сотрудник подключался к системе в последний раз

Rights

varchar(16)

Права сотрудника

Когда сотрудник подключается к административному приложению, он вводит свой идентификатор и пароль. Приложение проверяет, есть ли такой пользователь в таблице managers и правильно ли был указан пароль. Если все верно, приложение выбирает из поля Rights текстовое описание прав сотрудника и обновляет поле LastLogin, фиксируя момент его подключения к системе.

Чтобы создать данную таблицу в базе данных BookStore, запустите приложение SQL Server Enterprise Manager (если оно не было запущено ранее), а затем выберите из меню Tools строку SQL Server Query Analyzer. В результате будет запущено приложение SQL Server Query Analyzer, главное окно которого показано на рис. 14-7.

Рис. 14-7. Приложение SQL Server Query Analyzer

Следующий шаг очень важен.

Выберите в списке DB, расположенном в правой части инструментальной панели окна Query, базу данных BookStore, как это показано на рис. 14-7. Теперь мы будем запускать программы SQL в контексте именно этой базы данных.

Далее воспользуйтесь строкой Open в меню File, для выбора файла сценария SQL с именем dbo.managers.TAB, создающего таблицу managers. Содержимое этого файла представлено в листинге 14-1.

Листинг 14-1. Вы найдете в файле chap14\BookShopScripts\dbo.managers.TAB на прилагаемом к книге компакт-диске

Загрузив сценарий SQL в окно приложения SQL Server Query Analyzer, запустите его при помощи клавиши F5, кнопки запуска на инструментальной панели (с изображением треугольника зеленого цвета) или выбрав строку Execute из меню Query. Если вы не допустили ошибок при вводе сценария SQL, в нижней части окна Query появится сообщение «The command(s) completed successfully».

Таблица clients

Таблица clients содержит сведения, предоставленные посетителями Вашего магазина при регистрации, а также дополнительные, такие как дата регистрации и адрес IP, с которого выполнялась регистрация. Посетитель магазина работает с этой и еще одной таблицей при помощи созданного нами приложения покупателя Интернет-магазина.

Описание полей таблицы clients Вы найдете в табл. 14-7.

Таблица 14-7. Поля таблицы clients

Поле

Тип

Описание

ClientID

Int

Идентификатор записи таблицы clients (ключевое поле)

UserID

varchar(50)

Идентификатор покупателя, который он должен указывать при подключении к пользовательскому приложению Интернет-магазина

Password

varchar(50)

Пароль покупателя, выбранный им при регистрации

Language

varchar(50)

Предпочтительный язык для отображения страниц. В нашем демонстрационном примере это поле заполняется, но не проверяется

Money

Money

Общая сумма денег, потраченная покупателем в магазине за все время

Status

char(1)

Состояние покупателя (активный или неактивный). Не используется

LastLogin

Datetime

Дата и время последнего подключения покупателя к Интернет-магазину

UserName

varchar(50)

Полное имя покупателя, введенное им при регистрации

Email

varchar(80)

Адрес электронной почты, указанный покупателем при регистрации

mail

varchar(80)

Почтовый адрес покупателя

spam

char(3)

Флаг рассылки рекламных сообщений (в нашем приложении заполняется, но не проверяется)

RegisterDate

Datetime

Дата и время регистрации покупателя

RegisterIP

varchar(15)

Адрес IP, с которого выполнялась регистрация покупателя

Некоторые поля этой таблицы предусмотрены для будущего расширения проекта. Например, поле Language Вы можете использовать в том случае, если страницы Интернет-магазина готовятся на нескольких языках. В этом случае посетитель при регистрации может указать, какой язык должен быть использован при отображении страниц.

Поле Status можно использовать для проверки возможности удаления регистрационных записей покупателей, которые зарегистрировались, но долго не делали никаких покупок (например, больше года). При совершении покупки в это поле можно записывать какой-нибудь признак появления активности, например, символ «А». Отмеченные таким образом записи удалять не следует.

Поле spam можно использовать для организации автоматизированной рассылки рекламных сообщений покупателям Вашего магазина. Если при регистрации покупатель проявил такое желание, в это поле можно записать строку «YES», а если нет — строку «NO».

Поля RegisterDate и RegisterIP могут пригодиться для «разборок» с недобросовестными покупателями. С помощью утилит трассировки можно определить по адресу регистрации IP доменное имя сервера поставщика услуг Интернет, которым пользуется покупатель, а затем с его помощью вычислить и самого покупателя.

Хотя это и не предусмотрено в нашем проекте, вы можете собирать и хранить в таблице clients другую информацию о посетителях, например, версию использованной ими операционной системы, название и версию браузера, доменное имя рабочей станции. Вся эта информация поступает на сервер Web в заголовках HTTP и может быть легко получена сценарием ASP.

Для создания в базе BookStore таблицы clients воспользуйтесь приложением SQL Server Query Analyzer и файлом сценария SQL с именем dbo.clients.TAB (листинг 14-2).

Листинг 14-2. Вы найдете в файле chap14\BookShopScripts\dbo.clients.TAB на прилагаемом к книге компакт-диске

Обратите внимания на ограничения CONSTRAINT, определенные в таблице clients. Они задают начальные значения при добавлении в таблицу clients новых записей:

CREATE TABLE [dbo].[clients] (
  [ClientID] [int] IDENTITY (1, 1) NOT NULL ,
  [UserID] [varchar] (50) NOT NULL ,
  [Password] [varchar] (50) NOT NULL ,
  [Language] [varchar] (50) NOT NULL ,
  [Money] [money] NOT NULL
     CONSTRAINT [DF_clients_Money] DEFAULT (0),
  [Status] [char] (1) NOT NULL
     CONSTRAINT [DF_clients_Status] DEFAULT ('N'),
  [LastLogin] [datetime] NOT NULL
     CONSTRAINT [DF_clients_LastLogin] DEFAULT (0),
  [LoginCount] [int] NOT NULL
     CONSTRAINT [DF_clients_LoginCount] DEFAULT (0),
  [UserName] [varchar] (50) NOT NULL ,
  [Email] [varchar] (80) NOT NULL ,
  [mail] [varchar] (80) NULL ,
  [spam] [char] (3) NOT NULL
     CONSTRAINT [DF_clients_spam] DEFAULT ('no'),
  [RegisterDate] [datetime] NULL
     CONSTRAINT [DF_clients_RegisterDate] DEFAULT (getdate()),
  [RegisterIP] [varchar] (15) NULL ,
     CONSTRAINT [PK_clients] PRIMARY KEY NONCLUSTERED
  (
     [ClientID]
  ) ON [PRIMARY]
) ON [PRIMARY]

Например, поле spam инициализируется строкой «no», а в поле RegisterDate автоматически заносится текущая дата, полученная от встроенной функции getdate.

Состояние пользователя, хранящееся в поле Status, отмечается символом «N». Когда посетитель сделает первую покупку, Вы можете записать сюда другое значение, например, «А».

Поля UserID и Email сделаны уникальными:

CREATE UNIQUE INDEX [idxUserID] ON [dbo].[clients]([UserID]) ON [PRIMARY]
GO

CREATE UNIQUE INDEX [idxEMail] ON [dbo].[clients]([Email]) ON [PRIMARY]

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

Таблица books

В таблицу books сотрудники Вашего Интернет-магазина будут заносить сведения о продаваемых книгах. Для этого они будут использовать административное приложение. Покупатели так же будут обращаться к этой таблице, но с помощью другого приложения, созданного специально для них. Таблица books нужна покупателям для того, чтобы выбрать нужные им книги и положить их в свою виртуальную электронную «корзину».

Поля таблицы books описаны в табл. 14-8.

Таблица 14-8. Поля таблицы books

Поле

Тип

Описание

booksID

Int

Идентификатор записи таблицы books (ключевое поле)

Author

Varchar(50)

Автор книги

Title

Varchar(200)

Название книги

Publisher

Varchar(50)

Название издательства, выпустившего книгу

Price

Money

Стоимость книги в условных единицах

AddDate

Datetime

Дата и время добавления информации о книге в таблицу books

Annotation

Varchar(2048)

Аннотация на книгу

Цена книги указана в условных единицах, но это не потому, что курс национальной валюты может вдруг измениться. Так как Вы создаете магазин в Интернете, то покупатели могут использовать для оплаты различные валюты, и торгующему приложению придется выполнять пересчет стоимости. Тут-то и пригодятся наши условные единицы.

Обратите внимание на поле Annotation, предназначенное для хранения аннотации на книгу. Его максимальная длина составляет 2048 байт, что стало возможным только с появлением SQL Server версии 7.0. Максимально поле типа varchar может содержать 8000 символов, что позволяет хранить в поле Annotation довольно объемистые аннотации.

Создавая реальный проект Интернет-магазина, вы можете добавить в таблицу books и другие поля, например, номер ISBN, сведения о поставщиках и т.п.

Сценарий SQL, предназначенный для создания таблицы books, находится в файле dbo.books.TAB (листинг 14-3).

Листинг 14-3. Вы найдете в файле chap14\BookShopScripts\dbo.books.TAB на прилагаемом к книге компакт-диске

Ограничение CONSTRAINT на поле AddDate автоматизирует процесс записи даты добавления книги в таблицу books:

CREATE TABLE [dbo].[books] (
  [booksID] [int] IDENTITY (1, 1) NOT NULL ,
  [Author] [varchar] (50) NOT NULL ,
  [Title] [varchar] (200) NOT NULL ,
  [Publisher] [varchar] (50) NOT NULL ,
  [Price] [money] NOT NULL ,
  [AddDate] [datetime] NOT NULL
     CONSTRAINT [DF_books_AddDate] DEFAULT (getdate()),
  [Annotation] [varchar] (2048) NOT NULL ,
     CONSTRAINT [PK_books] PRIMARY KEY  NONCLUSTERED
  (
     [booksID]
  ) ON [PRIMARY]
) ON [PRIMARY]

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

Таблица orders

Когда покупатели отбирают понравившиеся им книги для покупки, происходит добавление записей в таблицу orders. Описание полей этой таблицы представлено в табл. 14-9.

Таблица 14-9. Поля таблицы orders

Поле

Тип

Описание

ordersID

Int

Идентификатор записи таблицы orders (ключевое поле)

booksID

Int

Идентификатор книги, отобранной для покупки

ClientID

Int

Идентификатор покупателя, отобравшего данную книгу

AddDate

Datetime

Дата и время отбора книги

BookPrice

money

Стоимость отобранной книги в условных единицах

Поля booksID и ClientID представляют собой внешние ключи к таблицам books и clients, соответственно. С помощью этих полей мы можем определить, какую книгу отобрал тот или иной покупатель.

Поле AddDate, хранящее дату и время отбора книги, можно использовать для автоматической очистки корзин от старых записей. Например, вы можете принудительно удалять записи об отобранных книгах, сделанные более года назад.

Сценарий SQL, создающий таблицу orders, представлен в листинге 14-4.

Листинг 14-4. Вы найдете в файле chap14\BookShopScripts\dbo.orders.TAB на прилагаемом к книге компакт-диске

Обратите внимание на ограничение CONSTRAINT поля AddDate:

CREATE TABLE [dbo].[orders] (
  [ordersID] [int] IDENTITY (1, 1) NOT NULL ,
  [booksID] [int] NOT NULL ,
  [ClientID] [int] NOT NULL ,
  [AddDate] [datetime] NOT NULL
     CONSTRAINT [DF_orders_AddDate] DEFAULT (getdate()),
  [BookPrice] [money] NOT NULL ,
     CONSTRAINT [PK_orders] PRIMARY KEY NONCLUSTERED
  (
     [ordersID]
  ) ON [PRIMARY]
) ON [PRIMARY]

С его помощью в данное поле автоматически записывается время и дата добавления книги в корзину покупателя.

Подготовка хранимых процедур

Для приложений нашего Интернет-магазина мы подготовили ряд хранимых процедур. Серверные сценарии, расположенные на страницах ASP наших приложений, будут обращаться к этим процедурам для выполнения всех операций с базой данных.

Для примера мы привели в листинге 14-5 исходный текст хранимой процедуры ClientLogin, предназначенной для подключения к Интернет-магазину зарегистрированных покупателей.

Листинг 14-5. Вы найдете в файле chap14\BookShopScripts\ dbo.ClientLogin.PRC на прилагаемом к книге компакт-диске

В качестве входных параметров мы передаем этой процедуре идентификатор пользователя @User и пароль пользователя @Pass:

CREATE PROCEDURE ClientLogin @User varchar(50), @Pass varchar(50), @Rights varchar(16) output AS

SELECT @Rights=UserID FROM clients WHERE UserID=@User AND Password=@Pass
UPDATE clients SET LastLogin=GETDATE() WHERE UserID=@User

Результат аутентификации записывается процедурой ClientLogin в выходной параметр @Rights. Попутно наша процедура обновляет поле LastLogin таблицы clients, записывая в нее время и дату подключения, полученные от встроенной функции GETDATE.

Сейчас мы не будем описывать подробно работу этой и других процедур, отложив это до разделов, посвященных описанию страниц ASP нашего магазина. Отметим только, что процедуры вы можете добавить в базу данных при помощи приложения SQL Server Query Analyzer.

После добавления процедур не забудьте выделить пользователям Интернета права на их выполнение. Для этого запустите приложение SQL Server Enterprise Manager, откройте базу данных BookStore и папку с хранимыми процедурами Stored Procedures. Выберите процедуру и щелчком правой клавиши мыши откройте страницу Stored Procedure Properties, показанную на рис. 14-8.

Рис. 14-8. Страница Stored Procedure Properties

Здесь вы можете редактировать текст процедуры. Для сохранения изменений щелкните кнопку OK. Что же касается прав на выполнение процедуры, то их нужно добавить при помощи кнопки Permissions. Открыв панель Object Properties, отметьте на вкладке Permissions переключатели в столбце EXEC в строках тех пользователей, которым нужно предоставить доступ на выполнение процедуры.

Создание источника данных

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

Откройте на компьютере, играющем роль сервера Web, папку Control Panel и сделайте двойной щелчок по пиктограмме ODBC Data Sources. После того как на экране появится панель ODBC Data Sources Administrator, откройте вкладку System DSN и нажмите кнопку Add. Вы увидите страницу мастера создания источников данных с названием Create New Data Source (рис. 14-9).

Рис. 14-9. Страница Create New Data Source

В списке, расположенном на этой странице, выберите драйвер SQL Server, а затем щелкните кнопку Finish. На экране появится первая страница мастера создания источника данных для SQL Server, показанная на рис. 14-10.

Рис. 14-10. Первая страница мастера создания источника данных для SQL Server

В поле Name этой страницы введите имя создаваемого источника данных — BookStore. В поле Description вы также можете ввести текстовое описание источника данных.

Далее в списке Server Вам нужно выбрать сервер базы данных, к которому будет выполняться подключение. Если серверы Web и SQL Server установлены на одном компьютере (как у нас), нужно выбрать в этом списке строку (local). Если же сервер SQL Server работает на другом компьютере. в этом списке вы должны выбрать нужный сервер базы данных.

Заполнив поля на первой странице, щелкните кнопку Next.

На следующей странице мастера (рис. 14-11), вы должны выбрать способ аутентификации при подключении к SQL Server.

Рис. 14-11. Выбор способа аутентификации

При использовании аутентификации Windows NT вы можете оставить переключатели в том состоянии, в котором они показаны на рис. 14-11. Щелкнув кнопку Client Configuration, можно выбрать сетевую библиотеку и указать параметры подключения для выбранной библиотеки (рис. 14-12).

Рис. 14-12. Выбор сетевой библиотеки и настройка ее параметров

При создании источника данных для нашего Интернет-магазина Вы можете оставить эти настройки в исходном состоянии.

Чтобы продолжить процесс, щелкните кнопку Next в панели выбора способа аутентификации, показанной на рис. 14-11. На экране появится третья панель мастера, с помощью которой нужно выбрать базу данных, выбираемую по умолчанию (рис. 14-13).

Рис. 14-13. Выбор базы данных по умолчанию

Остальные элементы управления, расположенные в этой панели, можно оставить в исходном состоянии.

Снова щелкните кнопку Next. В панели, показанной на рис. 14-14, выберите нужный язык системных сообщений и включите переключатель Use regional ettings when outputting currency, numbers, dates and times.

Рис. 14-14. Последняя панель мастера создания источника данных

Для завершения работы мастера щелкните в этой панели кнопку Finish. На экране появится описание конфигурации созданного источника данных (рис. 14-15).

Рис. 14-15. Описание конфигурации созданного источника данных

Теперь Вам нужно проверить работоспособность источника. Это можно сделать при помощи кнопки Test Data Source. Щелкните эту кнопку, и если Вы все сделали правильно, на экране появится сообщение об успешном завершении теста (рис. 14-16).

Рис. 14-16. Сообщение об успешной проверке источника данных

Теперь все готово для того, чтобы приступить к настройке виртуальных каталогов сервера Web и к созданию страниц ASP нашего Интернет-магазина.

Настройка сервера Web

После создания базы данных можно переходить к настройке сервера Web. Вам нужно создать виртуальные каталоги или виртуальные серверы Web для приложения покупателя (Front-офиса) и административного приложения (Back-офиса).

Наш Интернет-магазин состоит из двух приложений ASP. Первое приложение предназначено для сотрудников магазина и мы назовем его административным. Второе приложение будут запускать посетители Вашего магазина. Мы назовем его приложением покупателя.

Виртуальный каталог приложения покупателя BookShopClient

В виртуальном каталоге приложения покупателя будут находиться страницы ASP, доступные покупателям. Они предназначены для просмотра списка товаров (книг), отбора товаров в корзину и осуществления процесса покупки.

Этот виртуальный каталог, так же как и виртуальный каталог административного приложения. создается средствами управляющей консоли Microsoft Management Console. Укажите имя каталога как BookShopClient, проследив за тем, чтобы для него были разрешены чтение и исполнение сценариев. Для этого в панели BookShopClient Properties откройте вкладку Virtual Directory и включите переключатели Read и Script (если они были выключены).

Разрешите также отладку серверных и клиентских сценариев на вкладке App Debugging и отметив переключатели Enable ASP server-side script debugging и Enable ASP client-side script debugging. Для того чтобы эти изменения вступили в силу, закройте панель и перезагрузите компьютер.

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

Виртуальный каталог административного приложения BookShop

Этот виртуальный каталог содержит страницы ASP, предназначенные для просмотра только сотрудниками Вашего магазина. Обычные посетители не должны иметь к нему никакого доступа.

Создайте виртуальный каталог с именем BookShop, воспользовавшись для этого приложением Microsoft Management Console. Для ограничения доступа отредактируйте свойства виртуального каталога BookShop, открыв в панели BookShop Properties вкладку Directory Security (рис. 14-17).

Рис. 14-17. Настройка доступа к виртуальному каталогу

Прежде всего, на этой вкладке вы можете запретить доступ анонимных пользователей Интернета к данному каталогу. Для этого щелкните кнопку Edit в поле Anonymous Assess and Authentication Control. На экране появится панель Authentication Methods (рис. 14-18).

Рис. 14-18. Отмена доступа анонимных пользователей

Снимите в этой панели отметку с переключателя Allow Anonymous Access, оставив переключатель Windows NT Challenge/Response в отмеченном состоянии.

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

Щелкните кнопку Edit в поле IP Address and Domain Name Restrictions на вкладке Directory Security (рис. 14-17). Вы увидите панель редактирования списка адресов IP, показанную на рис. 14-19.

Рис. 14-19. Панель IP Address and Domain Name Restrictions

Отметьте в этой панели переключатель Denied Access. В результате к данному виртуальному каталогу будет запрещен доступ со всех адресов IP, за исключением перечисленных в списке. Список редактируется с помощью кнопок Add (добавление нового адреса), Remove (удаление адреса) и Edit (редактирование адреса).

Вы должны добавить в список адреса IP сотрудников вашего магазина, работающих с административным приложением. При этом нужно позаботиться о том, чтобы у них были постоянные, а не динамические адреса IP.

Дополнительный уровень безопасности административного приложения реализуется парольной системой ограничения доступа, встроенной в само приложение.

Приложение покупателя

Приложение покупателя будут запускать посетители Вашего магазина, поэтому при его реализации мы решили обойтись без клиентских сценариев. Это позволило нам расширить номенклатуру браузеров, способных правильно показывать страницы «публичной» части Интернет-магазина.

Прежде чем приступить к рассказу о внутренней реализации страниц ASP приложения покупателя, рассмотрим логику его работы.

Когда посетитель попадает на первую страницу приложения покупателя, в окне его браузера появляется форма, показанная на рис. 14-20.

Рис. 14-20. Вход для покупателей

Прежде чем совершать покупки, посетитель должен зарегистрироваться, выбрав среди всего прочего идентификатор (имя для входа) и пароль. Это позволит нам не только хранить в базе данных магазина индивидуальную информацию о покупателях, но и просто необходимо для создания в этой базе индивидуальных электронных  «корзин», куда покупатели будут откладывать товар перед оплатой.

Если посетитель уже зарегистрировался ранее, для того чтобы попасть в магазин ему нужно ввести в поле Имя свой идентификатор, а в поле Пароль — свой пароль. Новые пользователи должны зарегистрироваться, щелкнув кнопку Регистрация.

В тех случаях, когда указанный идентификатор пользователя отсутствует в регистрационной базе данных или когда пароль указан неправильно, посетитель получает сообщение о необходимости регистрации (рис. 14-21).

Рис. 14-21. Новые покупатели должны зарегистрироваться

Щелчок по ссылке Вам нужно зарегистрироваться отправляет его на входную страницу, показанную на рис. 14-20.

Таким образом, мы не сообщаем посетителю, допустил ли он ошибку при наборе идентификатора или при наборе пароля, а просто сообщаем о необходимости регистрации.

Форма регистрации новых посетителей показана на рис. 14-22.

Рис. 14-22. Регистрация нового покупателя

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

Как мы уже говорили раньше при описании полей таблицы clients, содержащей сведения о посетителях, поля идентификатор пользователя и электронного адреса E-Mail сделаны уникальными. Если при регистрации посетитель укажет идентификатор или адрес электронной почты, ранее записанные в базу данных другими посетителями, он получит сообщение об ошибке с предложением повторит регистрацию. Форма с этим сообщением показана на рис. 14-23.

Рис. 14-23. Сообщение об ошибке при регистрации

В случае успешной регистрации посетителю будет показано другое сообщение —приглашение для входа (рис. 14-24).

Рис. 14-24. Приглашение для входа

Щелкнув ссылку Входите!, посетитель вновь попадет на входную страницу, показанную на рис. 14-20. Теперь ему нужно ввести свой идентификатор и пароль, а затем войти при помощи кнопки Вход.

Выполнив описанные выше действия, покупатель, наконец, попадает на главную страницу магазина, состоящую из трех фреймов (рис. 14-25). Левый фрейм представляет собой меню команд, состоящее всего из двух строк — Выход и Оплатить покупки. Верхний фрейм содержит список книг, имеющихся в продаже, а в нижнем фрейме отображается содержимое корзины покупателя. При первом посещении магазина корзина будет пустой.

Заметим, что хотя фреймы и упрощают создание и сопровождение страниц сервера Web, некоторые браузеры (особенно старые) испытывают трудности при отображении фреймов. В реальном проекте Интернет-магазина лучше отказаться от применения фреймов, но мы будем их использовать для простоты изложения материала и сокращения объема листингов.

Рис. 14-25. Первое посещение магазина

Как видно из рис. 14-25, в правом верхнем фрейме отображается информация из таблицы books, описанной нами ранее. Эта информация записывается и редактируется сотрудниками Вашего магазина при помощи административного приложения, которое мы рассмотрим позже.

Справа от названия книги под ее стоимостью находится ссылка, щелкнув которую можно добавить книгу в корзину покупателя. Список отобранных книг появится в правом нижнем фрейме (рис. 14-26).

Рис. 14-26. Покупатель отобрал несколько книг в корзину

Ссылка Удалить из корзины позволит посетителю отказаться от покупки той или иной книги. Щелчок по этой ссылке приведет к тому, что фрейм корзины будет перерисован и в нем станет на одну позицию меньше.

В реальном магазине вы можете рассчитывать стоимость книг с учетом доставки, а также позволять посетителю указывать количество приобретаемых книг. Стоимость доставки может определяться автоматически, если при регистрации Вы будете требовать от посетителей выбирать из списка город и страну проживания. При этом Вам будет нужно добавить в базу данных магазина таблицу с информацией о стоимости доставки для различных регионов. Нужно будет также учесть способ доставки (поездом, самолетом, курьером и т.д.).

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

С помощью ссылки Оплатить покупки посетитель сможет осуществить процесс оплаты или сделать предварительный заказ. Мы рассмотрим соответствующие процедуры позже в этой главе, а сейчас перейдем к описанию исходных текстов страниц ASP приложения покупателя.

Файл global.asa

В корне виртуального каталога BookShopClient, созданного для страниц клиентского приложения, необходимо разместить файл global.asa (листинг 14-6).

Листинг 14-6. Вы найдете в файле chap14\BookShopClient\global.asa на прилагаемом к книге компакт-диске

В начале этого файла мы расположили ссылку на библиотеку типов ADO, нужную для использования констант в серверных сценариях ASP:

<!-- METADATA TYPE="typelib"
FILE="d:\program files\common files\system\ado\msado20.tlb" -->

Проверяя работу нашего приложения, отредактируйте путь, указанный в параметре FILE тега METADATA, таким образом, чтобы он указывал на файл msado20.tlb Вашего сервера Web.

Страницы входа и начальной регистрации

Несколько страниц приложения покупателя предназначены для аутентификации посетителей и для регистрации новых посетителей. Они взаимосвязаны и поэтому мы будем рассматривать их вместе.

Вход зарегистрированных посетителей

Форма входа зарегистрированных покупателей, показанная на рис. 14-20, определена в файле default.asp (листинг 14-6).

Листинг 14-6. Вы найдете в файле chap14\BookShopClient\default.asp на прилагаемом к книге компакт-диске

Вы должны настроить свой сервер Web таким образом, чтобы при просмотре виртуальных каталогов пользователю отправлялся файл с именем default.asp. Кроме того, следует запретить посетителям прямой просмотр содержимого виртуальных каталогов сервера Web.

Изучая листинг 14-6, вы можете заметить, что в нем находятся две формы. Первая форма предназначена для входа зарегистрированных покупателей:

<form ACTION="enter.asp" METHOD="post" TARGET="_top">
  <h2>Вход для покупателей</h2>
  <table BORDER="0" CELLPADDING="5" CELLSPACING="0">
     <tr>
       <td>Имя </td>
       <td><input SIZE="10" TYPE="EDIT" NAME="USR"> </td>
     </tr>
     <tr>
       <td>Пароль </td>
       <td><nobr>
       <input SIZE="10" TYPE="password" NAME="PWD">
     <input TYPE="submit" VALUE="Вход"></nobr></td>
     </tr>
  </table>
</form>  

Она ссылается на страницу enter.asp. Вторая форма содержит кнопку с надписью Регистрация, щелчок по которой отправляет посетителя на страницу регистрации regdataenter.asp:

<form ACTION="regdataenter.asp" METHOD="post" TARGET="_top">
  <h2>Пожалуйста, зарегистрируйтесь</h2>
  <table BORDER="0" CELLPADDING="5" CELLSPACING="0">
     <tr><td></td><td>
       <input type="submit" value="Регистрация" name="B1"></td>
     </tr>
  </table>
</form>   </td></tr>

Вначале мы рассмотрим исходный текст страницы enter.asp (листинг 14-7).

Листинг 14-7. Вы найдете в файле chap14\BookShopClient\enter.asp на прилагаемом к книге компакт-диске

При загрузке этой странице передается из формы содержимое полей с именами USR и PWD (соответственно, идентификатор посетителя и его пароль).

Серверный сценарий, расположенный на странице enter.asp, получает идентификатор пользователя и пароль, обращаясь к объекту Rerquest, а затем сохраняет соответствующие строки в переменных с именами sUser и sPassword:

var sUser=Request("USR")(1);
var sPassword=Request("PWD")(1);

Далее сценарий создает объект Connection и открывает соединение с источником данных, вызывая для этого метод Open:

var connect;
connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout = 10;
connect.Open("DSN=BookStore", "dbo", "");

С целью обработки ошибок эта и последующие операции с базами данных выполняются сценарием в блоке try.

Мы передали методу Open в качестве параметров имя источника базы данных Интернет-магазина BookStore, созданное нами ранее, имя владельца базы данных и пустую строку пароля. В реальном проекте мы рекомендуем определить отдельные учетные записи для работы с источником данных и пароли.

На следующем шаге сценарий создает объект Command, необходимый для выполнения хранимой процедуры аутентификации посетителя ClientLogin:

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "ClientLogin";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;

Хранимая процедура ClientLogin имеет два входных параметра (идентификатор и пароль посетителя) и один выходной (результат аутентификации).

Входные параметры определяются в объекте Command следующим образом:

cmd.Parameters.Append(cmd.CreateParameter(
  "User", adVarChar, adParamInput, 50, sUser));
cmd.Parameters.Append(cmd.CreateParameter(
  "Pass", adVarChar, adParamInput, 50, sPassword));

Имена параметров указаны как «User» и «Pass». Это текстовые строки, поэтому тип параметров мы указываем как adVarChar. Константа adParamInput определяет, что параметры «User» и «Pass» являются входными. Длина текстовых строк, передаваемых через данные параметры, не превышает 50 байт. И, наконец, значения параметров берутся из переменных sUser и sPassword.

Выходной параметр определяется аналогичным образом, но с применением константы adParamOutput:

var ParamOut = cmd.CreateParameter(
  "Rights", adVarChar, adParamOutput, 50, " ");

После формирования параметров они добавляются к команде методом Append, после чего команда выполняется при помощи метода Execute:

cmd.Parameters.Append(ParamOut);
cmd.Execute();

Если в процессе создания соединения с источником данных, формирования команды и ее параметров, а также при выполнении команды не возникло никаких ошибок, соединение закрывается методом Close:

connect.Close();

Строго говоря, можно не закрывать соединение подобным образом, так как после того как пользователь перейдет к просмотру другой страницы оно будет автоматически закрыто. Однако это может произойти не сразу (по умолчанию через 20 минут), поэтому для освобождения ресурсов сервера SQL Server мы закрываем соединение явным образом.

Далее мы проверяем значение, полученное от хранимой процедуры ClientLogin через параметр ParamOut.

Если аутентификация пользователя прошла успешно, в этом параметре будет находиться значение, отличное от null. В этом случае мы сохраняем в переменных сеанса результат аутентификации, признак успешной идентификации и идентификатор пользователя, а затем передаем управление странице main.asp:

if(ParamOut.value != null)
{
  Session("Rights")=ParamOut.value;
  Session("Ok")="Ok";
  Session("UserID")=sUser;
  Response.Redirect("main.asp");
}
else
{
  Session("Ok")="";
  Session("UserID")="";
  Session("Rights")="";

Переменная сеанса с именем Rights никак не используется нашим приложением, хотя вы можете использовать ее для дифференциации посетителей. В этом случае в таблице clients Вы можете предусмотреть поле Rights и хранить в нем права пользователей, устанавливая их в зависимости от тех или иных условий. Например, пользователи, сделавшие покупки на значительные суммы, могут получить доступ к дополнительным страницам Вашего магазина.

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

И, наконец, переменная сеанса UserID идентифицирует покупателя и используется, например, для формирования его персональной корзины.

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

Обработка ошибок

В том случае, когда при обращении к базе данных возникли ошибки, мы их обрабатываем в блоке catch. Использованная при этом методика была описана ранее, поэтому здесь мы только скажем, что сообщение об ошибке передается странице error.asp:

Response.Redirect(
 
"error.asp?ERROR=enter.asp"+"&ERRMSG="+serrMessage);

При этом через параметр ERROR мы передаем имя файла страницы, в которой произошла ошибка, а в переменной ERRMSG — сообщение об ошибке, подготовленное в блоке catch.

Исходный текст страницы error.asp мы представили в листинге 14-8.

Листинг 14-8. Вы найдете в файле chap14\BookShopClient\error.asp на прилагаемом к книге компакт-диске

Здесь мы информируем посетителя о том, что произошла ошибка в приложении, для исправления которой необходимо вмешательство администратора сервера Web. Далее отображается название страницы, в которой произошла ошибка, и текст сообщения об ошибке:

<h2>Ошибка в приложении</h2>
<p>Обратитесь к администратору сервера Web. </p>
<p>[<%=Request("ERROR")%>]<br><%=Request("ERRMSG")%>

На рис. 14-27 мы показали сообщение, возникающее в том случае, если вы пытаетесь создать соединение с несуществующим источником данных.

Рис. 14-27. Сообщение об ошибке при соединении с источником данных

Другое сообщение появится в случае, если Вы забудете назначить права доступа к хранимой процедуре:

[enter.asp]
[-2147217911][Microsoft][ODBC SQL Server Driver][SQL Server]EXECUTE permission denied on object 'ClientLogin', database 'BookStore', owner 'dbo'.

Кстати, если мы вовсе опустим обработку ошибок на странице enter.asp, то ошибка все равно будет обработана, но уже системой интерпретации страниц ASP. При этом в случае, например, отсутствия прав на выполнение хранимой процедуры в окне браузера посетителя появится сообщение, показанное на рис. 14-28.

Рис. 14-28. Сообщение об ошибке, отображаемое интерпретатором ASP

Хотя оно содержит даже больше информации, нужной для отладки страницы (дополнительно отображается номер строки, в которой произошла ошибка), пользователю оно будет непонятно. Обрабатывая ошибки самостоятельно, мы можем рекомендовать пользователю выполнять те или иные действия в зависимости от логики работы приложения или от того, где возникла ошибка, а также в ряде случаев полностью ликвидировать ее последствия незаметно от пользователя.

Хранимая процедура ClientLogin

Теперь мы расскажем Вам о том, как устроена хранимая процедура ClientLogin, которая вызывается из сценария страницы enter.asp и выполняет аутентификацию пользователей приложения посетителей магазина.

Исходный текст хранимой процедуры ClientLogin приведен в листинге 14-9.

Листинг 14-9. Вы найдете в файле chap14\BookShopScripts\dbo.ClientLogin.PRC на прилагаемом к книге компакт-диске

Процедура ClientLogin имеет два входных параметра @User и @Pass и один выходной @Rights:

CREATE PROCEDURE ClientLogin @User varchar(50), @Pass varchar(50), @Rights varchar(16) output AS

SELECT @Rights=UserID FROM clients WHERE UserID=@User AND Password=@Pass
UPDATE clients SET LastLogin=GETDATE() WHERE UserID=@User

С помощью оператора SELECT процедура выбирает идентификатор пользователя из столбца UserID таблицы clients, причем такого, что этот идентификатор (записанный в этом столбце) совпадает с содержимым параметра @User. Кроме того, проверяется совпадение пароля пользователя (хранящегося в столбце Password) и содержимого переменной @Pass.

Если в результате выполнения такого запроса в таблице clients будет найдена подходящая запись, считается, что аутентификация прошла успешно. С помощью оператора UPDATE процедура ClientLogin обновляет поле LastLogin найденного пользователя, записывая в него дату и время подключения, полученные от функции GETDATE.

Определение фреймов главной страницы

После успешной аутентификации страница enter.asp загружает в окно браузера посетителя страницу определения фреймов приложения покупателя с именем main.asp. Исходный текст этой страницы, подготовленной  при помощи Microsoft FrontPage, Вы найдете в листинге 14-10.

Листинг 14-10. Вы найдете в файле chap14\BookShopClient\main.asp на прилагаемом к книге компакт-диске

С помощью тегов <FRAMESET> и <FRAME> мы определили три фрейма с именами left, rtop и rbottom.

<frameset cols="150,*">
  <frame name="left" scrolling="no" noresize target="rtop" src="toc.asp">
  <frameset rows="57%,*">
     <frame name="rtop" target="rbottom" src="booklist.asp">
     <frame name="rbottom" src="order.asp?FIRST=1">
  </frameset>
  <noframes>
  <body>
  <p>Для посещения нашего сервера нужен браузер,
  способный работать с фреймами.</p>
  </body>
  </noframes>
</frameset>

Фрейм left загружается страницей toc.asp, содержащей меню команд приложения покупателя. Это команды Выход и Оплатить покупки. Фрейм rtop используется для отображения списка книг, имеющихся в продаже и загружается страницей booklist.asp. И, наконец, фрейм rbottom используется для показа содержимого корзины с книгами, отобранными посетителем для покупки. Он загружается страницей order.asp с параметром FIRST, равным единице (о назначении этого параметра Вы узнаете позже при изучении исходного текста страницы order.asp).

Тег <NOFRAMES> используется для формирования строк HTML, отображаемых при загрузке данного документа в окно браузера, не способного работать с фреймами. Здесь мы просто сообщаем пользователю, что ему нужно обновить свой браузер.

Для исключения возможности прямой загрузки страницы main.asp в обход страницы аутентификации покупателей мы включили в исходный текст этой и других страниц приложения покупателя файлы header.asp и footer.asp. Для включения содержимого файлов мы использовали оператор #include, доступный в страницах ASP:

<%@ LANGUAGE = "JScript" %>
<!-- #include file="header.asp" -->
<html>
<head>
<title>
Книжный магазин</title>
. . .
</html>
<!-- #include file="footer.asp" -->

Исходные тексты этих файлов были приведены в предыдущей главе (листинги 3-19 и 3‑20), поэтому мы не будем здесь их повторять. Напомним только, что при загрузке любой страницы, в начало которой вставлен файл header.asp, выполняется проверка содержимого переменной сеанса с именем Ok. Если аутентификация пользователя прошла успешно, сценарий файла header.asp вставляет в документ теги <HTML> и <BODY>, а при неудаче — тег <META>, принудительно направляющий браузер на страницу аутентификации default.asp.

В результате все, что увидит посетитель, попытавшийся напрямую загрузить в окно своего браузера страницу main.asp, это страница default.asp, предлагающая ввести идентификатор и пароль, или выполнить регистрацию.

Страница меню команд

В левом фрейме страницы приложения покупателя расположено меню команд, состоящее из двух ссылок — Выход и Оплатить покупки. Исходный текст данного фрейма Вы найдете в листинге 14-11.

Листинг 14-11. Вы найдете в файле chap14\BookShopClient\toc.asp на прилагаемом к книге компакт-диске

Ссылка Выход отправляет покупателя на страницу default.asp, предлагающую ввести идентификатор и пароль зарегистрированного покупателя или выполнить регистрацию нового покупателя.

<a href="../BookShopClient/default.asp"
 
target="_top">Выход</a><br>

Ссылка Оплатить покупки используется для загрузки страницы makeorder.asp. Эта страница реализует процесс оплаты и будет рассмотрена позже в этой главе.

<a href="../BookShopClient/makeorder.asp"
 
target="_top">Оплатить покупки</a></p>

Страница просмотра списка книг

На странице просмотра списка книг, расположенной в файле booklist.asp (листинг 14-12) посетитель может выбрать для покупки понравившиеся ему книги. Эта страница формируется из таблицы books, содержимое которой готовится сотрудниками Интернет-магазина с помощью административного приложения.

Листинг 14-12. Вы найдете в файле chap14\BookShopClient\booklist.asp на прилагаемом к книге компакт-диске

Особенностью сценария, расположенного на этой странице, является работа с набором записей Recordset, полученным в результате работы хранимой процедуры.

В начале своей работы сценарий создает соединение с источником данных и открывает его. Эта операция выполняется точно таким же образом, как и в только что рассмотренном сценарии на странице enter.asp:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

Теперь нам нужно запустить на выполнение хранимую процедуру, возвращающую набор записей из таблицы books. Вместо того чтобы создавать команду, определять ее параметры и запускать методом Execute, как это делалось раньше, мы используем другой метод для запуска хранимой процедуры.

Набор записей создается явным образом при помощи метода CreateObject объекта Server:

rs = Server.CreateObject("ADODB.Recordset")

После этого мы его открываем, указывая методу Open объекта Recordset имя выполняемой хранимой процедуры ListBooks, соединение с источником данных connect и другие параметры:

rs.Open("ListBooks", connect,
  adOpenForwardOnly, adLockReadOnly, adCmdStoredProc);

Константа adOpenForwardOnly, передаваемая методу Open в качестве третьего параметра, определяет для открываемого набора записей тип курсора, предназначенного для просмотра записей только в одном (прямом) направлении.

Константа adLockReadOnly сообщает ADO, что полученный набор записей изменяться не будет, поэтому его не нужно блокировать.

И, наконец, константа adCmdStoredProc, передаваемая методу Open через последний параметр, указывает, что первый параметр метода задает имя хранимой процедуры, подлежащей выполнению.

После получения набора записей мы проверяем свойство EOF. Если оно хранит значение True, это означает что полученный набор записей пуст. В этом случае вместо  списка книг мы показываем в верхнем правом фрейме сообщение Нет записей:

if(rs.EOF)
{%>
<TR><TD COLSPAN=4 ALIGN="CENTER">[Нет записей]</TD></TR>
<%}
else {…}

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

В цикле мы последовательно просматриваем строки набора записей, перемещаясь по ним при помощи метода MoveNext, определенного в объекте Recordset. Условием завершения цикла является равенство свойства rs.EOF значению True:

<h2>Сегодня в продаже</h2>
<TABLE BORDER=1>
<%
while (!rs.EOF)
{
%>
<tr><td><b><%=rs.Fields("Author")%>. <%=rs.Fields("Title")%></b>
<br><i><%=rs.Fields("Publisher")%></i></td>
<td><%=rs.Fields("Price")%> у.е.<br>
<a href="order.asp?ID=<%=rs.Fields("booksID")%>&FIRST=0"
target="rbottom">Положить в корзину</A>
</td><tr>
<tr><td colspan=2>Аннотация:<br>
<small><%=rs.Fields("Annotation")%></small></td><tr>
<%
  rs.MoveNext();
}
rs.Close();
}
connect.Close();
}
catch (ex)
{
. . .
}
%>
</TABLE>

Для ссылки на поля набора записей мы используем имена соответствующих столбцов, из которых формируются строки набора. Содержимое полей набора вставляется в ячейки формируемой таблицы с помощью конструкций вида «<%=rs.Fields("Author")%>».

Для каждой книги мы вставляем в создаваемую таблицу ссылку на страницу order.asp, с помощью которой можно добавить книгу в электронную корзину покупателя:

<a href="order.asp?ID=<%=rs.Fields("booksID")%>&FIRST=0"
  target="rbottom">Положить в корзину</A>

Когда пользователь щелкнет ссылку, будет загружена страница order.asp. При этом ей будут переданы два параметра — идентификатор книги ID и флаг FIRST.

Параметр ID содержит идентификатор, по которому можно найти книгу в таблице books нашей базы данных. Без него мы бы не знали, какую именно книгу нужно добавить в корзину. Что же касается флага FIRST, то его значение, равное 0, говорит о том, что страница order.asp загружается для добавления новой книги в список отобранных книг, а не для простого просмотра этого списка.

Когда обработка набора записей закончена, мы должны закрыть этот набор методом Close объекта Recordset:

rs.Close();

Вслед за этим мы закрываем и соединение с источником данных, вызывая метод Close объекта Connection:

connect.Close();

Исходный текст хранимой процедуры ListBooks, запускаемой на выполнение серверным сценарием страницы booklist.asp, представлен в листинге 14-13.

Листинг 14-13. Вы найдете в файле chap14\BookShopScripts\dbo.ListBooks.PRC на прилагаемом к книге компакт-диске

Эта процедура очень проста. С помощью оператора SELECT она выбирает несколько полей из таблицы books:

CREATE PROCEDURE ListBooks  AS
SELECT booksID,Author, Title, Publisher, Price, AddDate,Annotation
FROM books

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

Добавление книги в корзину

Для того чтобы добавить книгу в свою корзину, покупатель щелкает ссылку Положить в корзину, расположенную в строке и названием этой книги. Об этой ссылке мы рассказывали в предыдущем разделе: она вызывает страницу order.asp с параметрами ID и FIRST.

На самом деле страница order.asp выполняет двойную функцию. Когда мы вызываем ее с параметром FIRST, равным 1, она просто отображает содержимое корзины покупателя. Если же значение этого параметра равно 0, перед таким отображением происходит добавление выбранной книги в корзину.

В следующем разделе мы рассмотрим выполнение и той, и другой операции.

Страница просмотра содержимого корзины

Особенностью страницы просмотра содержимого корзины является то, что она может выполнять одно или два обращения к базе данных в зависимости от значения параметра FIRST. Если этот параметр равен 0, сценарий вначале запускает хранимую процедуру AddToOrder, добавляющую выбранную книгу к корзине, а затем процедуру ListOrders, предназначенную для просмотра содержимого корзины.

Рассмотрим исходный текст страницы order.asp, представленный в листинге 14-14.

Листинг 14-14. Вы найдете в файле chap14\BookShopClient\order.asp на прилагаемом к книге компакт-диске

Для обработки ошибок, возникающих при обращениях к базе данных, мы предусмотрели единый блок catch. Поэтому блок try так же один.

Сразу после того, как страница получит управление, сценарий получает идентификатор пользователя и сохраняет его в локальной переменной с именем ClientID.

var ClientID=Session("UserID");

Этот идентификатор будет нужен для отбора тех записей в таблице orders, которые имеют отношение к данному покупателю.

Далее сценарий анализирует содержимое переменной сеанса с именем FIRST. Если оно не равно 1, то страница был вызвана для добавления новой книги в корзину покупателя.

В этом случае мы извлекаем идентификатор добавляемой книги ID и сохраняем его в локальной переменной booksID, а затем устанавливаем соединение с источником данных обычным способом.

Затем мы создаем команду cmd как объект Command  и готовим параметры для запуска хранимой процедуры AddToOrder. Этой процедуре нужно передать два входных параметра — идентификатор добавляемой книги booksID и идентификатор покупателя, добавившего книгу ClientID. После этого команда запускается на выполнение методом Execute:

if(Request("FIRST")(1) != 1)
{
  var booksID=Request("ID")(1);
  var connect;
  var cmd;
  connect = Server.CreateObject("ADODB.Connection");
  connect.ConnectionTimeout = 15;
  connect.CommandTimeout = 10;
  connect.Open("DSN=BookStore", "dbo", "");
 
  cmd = Server.CreateObject("ADODB.Command");
  cmd.CommandText = "AddToOrder";
  cmd.CommandType = adCmdStoredProc;
  cmd.ActiveConnection = connect;
 
  cmd.Parameters.Append(cmd.CreateParameter(
     "booksID", adVarChar, adParamInput, 50, booksID));
 
  cmd.Parameters.Append(cmd.CreateParameter(
     "ClientID", adVarChar, adParamInput, 50, ClientID));

  cmd.Execute();
}

Теперь нам нужно отобразить в правом нижнем фрейме главного окна приложения покупателя обновленное содержимое корзины. Чтобы не устанавливать повторное соединение с источником данных (оно уже было установлено для запуска хранимой процедуры AddToOrder), мы повторно анализируем параметр FIRST. Это позволяет нам сэкономить время и ресурсы сервера за счет исключения повторного соединения с источником данных:

if(Request("FIRST")(1) == 1)
{
  connect = Server.CreateObject("ADODB.Connection");
  connect.ConnectionTimeout = 15;
  connect.CommandTimeout = 10;
  connect.Open("DSN=BookStore", "dbo", "");
}

В любом случае нам нужно подготовить команду запуска хранимой процедуры ListOrders, возвращающую набор записей для книг, отобранных данным посетителем магазина. Эта процедура принимает только один параметр — идентификатор посетителя ClientID.

Запуск процедуры выполняется с помощью метода Execute:

cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "ListOrders";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;
 
cmd.Parameters.Append(cmd.CreateParameter(
  "ClientID", adVarChar, adParamInput, 50, ClientID));

var rs;
rs=cmd.Execute();

Данный метод возвращает набор записей, образовавшихся в результате выполнения команды.

На следующем этапе сценарий формирует в окне фрейма таблицу с названиями книг, отобранных покупателями. эта таблица создается в цикле путем последовательного перебора записей набора rs методом MoveNext.

<h2>Вы отобрали для покупки</h2>
<TABLE BORDER=1>
<%
while (!rs.EOF)
{
%>
<tr><td><b><%=rs.Fields("Author")%>. <%=rs.Fields("Title")%></b>
<br><i><%=rs.Fields("Publisher")%></i></td>
<td><%=rs.Fields("Price")%> у.е.<br>
<a href="delorder.asp?ID=<%=rs.Fields("booksID")%>" target="rbottom">Удалить из корзины</A>
</td><tr>
<%
  rs.MoveNext();
}
%>
</TABLE>

Чтобы пользователь, передумавший покупать книгу, смог удалить ее из корзины, мы вставляем рядом с названием каждой книги ссылку следующего вида:

<a href="delorder.asp?ID=<%=rs.Fields("booksID")%>"   target="rbottom">Удалить из корзины</A>

Здесь выполняется вызов страницы delorder.asp, причем в качестве параметра эта страница получает идентификатор удаляемой книги. Что же касается идентификатора покупателя, то эту информацию страница delorder.asp «добывает» самостоятельно из переменной сеанса с именем UserID.

После завершения формирования таблицы сценарий закрывает набор записей и ненужное больше соединение с источником данных:

rs.Close();
connect.Close();

На странице order.asp вызываются две хранимые процедуры с именами AddToOrder и ListOrders. Расскажем о том, как они работают.

Исходный текст процедуры AddToOrder, предназначенной для добавления новых книг в корзину покупателя, показан в листинге 14-15.

Листинг 14-15. Вы найдете в файле chap14\BookShopScripts\dbo.AddToOrder.PRC на прилагаемом к книге компакт-диске

В рамках этой процедуры последовательно выполняются обращения к двум таблицам — к таблице client, содержащей сведения о посетителях, и к таблице orders, в которой хранятся личные корзины покупателей.

Сначала процедура AddToOrder должна определить идентификатор записи в таблице clients, соответствующий идентификатору покупателя, передаваемому в процедуру через входной параметр @ClientID.

Это задачу решает первый оператор SELECT. Найденный идентификатор сохраняется в переменной @nClientID типа INT и затем используется при добавлении записей в таблицу orders:

CREATE PROCEDURE AddToOrder @booksID varchar(50),
 
@ClientID varchar(50) AS

DECLARE @nClientID INT
SELECT @nClientID=clients.ClientID FROM clients

WHERE UserID=@ClientID

Второй оператор SELECT определяет стоимость выбранной книги по ее идентификатору и записывает в переменную @bookPrice:

DECLARE @bookPrice MONEY
SELECT @bookPrice=Price FROM books WHERE booksID=@booksID

Оператор INSERT добавляет в таблицу orders новую запись, заполняя поля идентификатора выбранной книги booksID, идентификатора покупателя, отобравшего книгу в корзину ClientID и стоимость книги bookPrice:

INSERT orders (booksID, ClientID, bookPrice)
VALUES(@booksID, @nClientID,@bookPrice)

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

Исходный текст хранимой процедуры ListOrders вы найдете в листинге 14-16.

Листинг 14-16. Вы найдете в файле chap14\BookShopScripts\dbo.ListOrders.PRC на прилагаемом к книге компакт-диске

Она получает единственный входной параметр @ClientID — идентификатор покупателя, содержимое корзины которого необходимо извлечь из таблицы orders.

Эта операция выполняется в два приема.

Вначале процедура ListOrders получает идентификатор записи покупателя, пользуясь содержимым переменной @ClientID. Этот идентификатор сохраняется в переменной @nClientID:

CREATE PROCEDURE ListOrders @ClientID varchar(50) AS
DECLARE @nClientID INT
SELECT @nClientID=clients.ClientID FROM clients

WHERE UserID=@ClientID

Затем выполняется оператор SELECT, возвращающий информацию о книгах, выбранных данным посетителем. Она получается с помощью объединения таблиц orders и books оператором JOIN:

SELECT books.booksID, books.Author, books.Title, books.Publisher, books.Price FROM orders
JOIN books ON orders.booksID=books.booksID
WHERE orders.ClientID=@nClientID

Удаление книги из корзины

Если посетитель передумал покупать книгу, отобранную в корзину, он может удалить ее оттуда, щелкнув ссылку Удалить из корзины, расположенную рядом с книгой. При этом будет загружена страница delorder.asp (листинг 14-17).

Листинг 14-17. Вы найдете в файле chap14\BookShopClient\delorder.asp на прилагаемом к книге компакт-диске

Первое действие, выполняемое сценарием сразу после загрузки страницы — получение из переменной сеанса UserID идентификатора посетителя и сохранение этого идентификатора в переменной ClientID:

var ClientID=Session("UserID");

Далее сценарий запускает хранимую процедуру DelOrder, передавая ей два параметра:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");
var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "DelOrder";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;
 
cmd.Parameters.Append(cmd.CreateParameter("ClientID", adVarChar, adParamInput, 50, ClientID));
cmd.Parameters.Append(cmd.CreateParameter("bookID", adVarChar, adParamInput, 50, Request("ID")(1)));
cmd.Execute();

Первый параметр с именем ClientID хранит только что упомянутый идентификатор посетителя, удаляющего книгу из своей корзины. Второй параметр называется bookID и передается в страницу delorder.asp из страницы order.asp. Он содержит идентификатор удаляемой книги.

После удаления книги из корзины нам нужно обновить правый нижний фрейм, отображающий содержимое корзины покупателя. Мы это делаем с помощью метода Redirect объекта Response:

Response.Redirect("order.asp?FIRST=1");

Обратите внимание, что при загрузке страницы order.asp мы указываем параметр FIRST, равный единице. Если Вы помните, это значение говорит о том, что нужно показать текущее содержимое корзины, не выполняя над ней никаких операций.

Исходный текст хранимой процедуры DelOrder представлен в листинге 14-18.

Листинг 14-18. Вы найдете в файле chap14\BookShopScripts\dbo.DelOrder.PRC на прилагаемом к книге компакт-диске

Процедура DelOrder состоит из двух шагов.

На первом шаге мы извлекаем из таблицы clients идентификатор записи посетителя по его идентификатору, полученному процедурой через параметр @ClientID.

CREATE PROCEDURE DelOrder @ClientID varchar(50), @bookID varchar(50) AS
DECLARE @nClientID INT
SELECT @nClientID=clients.ClientID FROM clients
WHERE UserID=@ClientID

На втором шаге мы удаляем из таблицы orders все записи о книгах с идентификатором @bookID, добавленные данным посетителем.

DELETE orders
WHERE booksID=@bookID AND ClientID=@nClientID

Административное приложение Back-офиса

Теперь мы может перейти к описанию второй части нашего проекта Интернет-магазина — административного приложения, предназначенного для управления работой магазина. С помощью этого приложения Ваши сотрудники смогут редактировать список книг, имеющихся в продаже, формировать и редактировать список персонала магазина и решать другие административные задачи. Обычные посетители не должны иметь к этому приложению никакого доступа.

Прежде чем приступить к работе с административным приложением, Вы должны ввести идентификатор администратора и пароль на странице аутентификации (рис. 14-29).

Рис. 14-29. Вход в административное приложение

Если административное приложение запускается в самый первый раз и база данных администраторов пуста, в нее автоматически добавляется введенный идентификатор и пароль. Таким образом, кто первый подключился к системе, тот и стал администратором.

После успешного ввода пароля на экране появляется главная страница административного приложения, показанная на рис. 14-30.

Рис. 14-30. Главная страница административного приложения сразу после входа

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

Первое, что должен сделать администратор, войдя в систему, это определение списка управляющего персонала магазина. Для этого он должен воспользоваться командой Управляющий персонал. После щелчка по соответствующей ссылке в правом фрейме появится список персонала (рис. 14-31).

Рис. 14-31. Список управляющего персонала

После первого запуска в этом списке будет только одна запись для первого подключившегося администратора. С помощью ссылки Новый сотрудник Вы можете добавить другие записи. Если по ней щелкнуть мышью, в правом фрейме появится форма регистрации нового сотрудника (рис. 14-32).

Рис. 14-32. Добавление нового сотрудника

Здесь Вам необходимо определить идентификатор и пароль сотрудника, а также его права (или, если хотите, функциональные обязанности).

Для добавления сотрудника в базу данных щелкните кнопку Создать.

С помощью ссылки Изменить, расположенной напротив каждой записи списка персонала, вы можете отредактировать идентификатор, пароль и права сотрудника. Соответствующая форма показана на рис. 14-33.

Рис. 14-33. Редактирование учетной записи сотрудника

После внесения изменений щелкните кнопку Сохранить изменения, и они будут записаны в базу данных магазина.

Ссылки Удалить в списке сотрудников позволяют удалить учетные записи. Если щелкнуть такую ссылку, соответствующая запись будет удалена из базы данных.

Если щелкнуть в левом фрейме ссылку Книги, на экране появится список книг, имеющихся в продаже (рис. 14-34).

Рис. 14-34. Просмотр списка книг, имеющихся в продаже

Первоначально этот список будет пустым. чтобы добавить в него новую книгу, щелкните ссылку Новая книга. На экране появится форма, предназначенная для добавления новой книги (рис. 14-35).

Рис. 14-35. Добавление в список новой книги

Здесь Вам необходимо ввести автора книги, ее название, выбрать издателя, указать стоимость и вписать аннотацию. Для того чтобы добавить книгу в базу данных, следует щелкнуть кнопку Добавить.

В любой момент можно отредактировать описание книги, хранящееся в базе данных магазина. Для этого достаточно в списке книг щелкнуть ссылку Изменить. В правый фрейм будет загружена страница с формой для редактирования сведений о книге (рис. 14-36).

Рис. 14-36. Редактирование сведений о книге

Чтобы обновить содержимое базы данных после редактирования полей этой формы, щелкните кнопку Сохранить изменения.

И, наконец, чтобы удалить книгу из базы данных, щелкните ссылку Удалить напротив названия книги в списке просмотра, показанном на рис. 14-34.

Команда Покупатели, расположенная в левом фрейме страницы административного приложения, открывает доступ для просмотра таблицы посетителей client и редактирования некоторых ее полей. Если щелкнуть эту ссылку, на экране появится форма, позволяющая задать критерии поиска клиентов (рис. 14-37).

Рис. 14-37. Поиск покупателей

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

Если оставить поля идентификатора пользователя и адреса E-Mail незаполненными, после щелчка по ссылке Поиск в правом фрейме появится список всех покупателей, зарегистрированных в указанный период времени. Если дополнительно снять отметку с переключателя искать по дате регистрации:, будет составлен список всех зарегистрированных покупателей.

Так как поиск записей посетителей выполняется с применением оператора сравнения LIKE, в полях Идентификатор покупателя и Адрес E-Mail можно использовать символы шаблонов, стандартные для языка Transact-SQL. Это такие символы, как «%[]^_».

На рис. 14-38 показан полный список зарегистрированных покупателей, полученный с помощью только что описанной формы поиска.

Рис. 14-38. Полный список зарегистрированных покупателей

С помощью команды Изменить Вы можете отредактировать некоторые параметры регистрации выбранного пользователя (рис. 14-39).

Рис. 14-39. Редактирование параметров регистрации покупателя

Для сокращения объемов листингов мы отображаем здесь не все параметры регистрации. При создании реального проекта Вы, однако, можете расширить набор редактируемых параметров, добавив в него все остальные поля таблицы clients.

Команда Корзина позволяет сотруднику магазина просмотреть содержимое корзины выбранного пользователя (рис. 14-40).

Рис. 14-40. Просмотр содержимого корзины покупателя

Здесь мы не предусмотрели возможность удаления книг из корзины, так как считаем, что это должен делать сам покупатель. Что же касается очистки корзин покупателей от старых записей, то для выполнения этой работы Вы можете предусмотреть отдельную команду в административном приложении.

Вернемся к списку покупателей.

С помощью ссылки Удалить сотрудник магазина может удалить регистрационную запись выбранного покупателя, если он не активен. Однако такая операция должна выполняться осторожно. Например, если покупатель отобрал товар в корзину или уже делал покупки в Вашем магазине, его, возможно, не следует удалять.

Если щелкнуть ссылку Удалить, на экране появится временная модальная диалоговая панель с предупреждающим сообщением, показанная на рис. 14-41.

Рис. 14-41. Предупреждающее сообщение

Вы можете в этой панели отказаться от удаления, щелкнув ссылку Отменить, или подтвердить свои намерения при помощи ссылки Удалить.

Если корзина удаляемого покупателя пуста, операция будет выполнена успешно. Об этом будет сказано в сообщении, показанном на рис. 14-42.

Рис. 14-42. Сообщение об успешном удалении учетной записи покупателя

Если же покупатель отобрал книги в корзину, наше административное приложение откажется удалять его учетную запись, сообщив об этом администратору (рис. 14-43).

Рис. 14-43. Сообщение о невозможности удалении учетной записи активного покупателя

Файл global.asa

В корне виртуального каталога BookShop, созданного нами для страниц административного приложения, необходимо поместить файл global.asa. Вы можете использовать здесь тот же самый файл, что и для приложения покупателя. Его исходный текст мы уже приводили в листинге 14-6.

Страницы входа

Рассмотрим исходные тексты страниц, предназначенные для входа сотрудников Вашего Интернет-магазина в административное приложение.

Страница default.asp (листинг 14-19) должна загружаться в окно браузера по умолчанию, когда сотрудник магазина пытается просмотреть содержимое виртуального каталога административного приложения.

Листинг 14-19. Вы найдете в файле chap14\BookShop\default.asp на прилагаемом к книге компакт-диске

В форме, расположенной на той странице, необходимо ввести идентификатор и пароль, а затем щелкнуть кнопку Вход:

<FORM ACTION="enter.asp" METHOD="post" TARGET="_top">
  <H1>
Добро пожаловать!</H1>
  <TABLE BORDER=0 CELLPADDING=5 CELLSPACING=0>
     <TR><TD>
Имя</TD><TD>
       <INPUT SIZE=10 TYPE="EDIT" NAME="USR">
     </TD></TR>
     <TR><TD>
Пароль</TD><TD><nobr>
       <INPUT SIZE=10 TYPE="password" NAME="PWD">
       <INPUT TYPE="submit" VALUE="
Вход"></nobr>
     </TD></TR>
  </TABLE>
</FORM></TD></TR>

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

После щелчка кнопки Вход управление передается странице Enter.asp, выполняющей аутентификацию (листинг 14-20).

Листинг 14-20. Вы найдете в файле chap14\BookShop\Enter.asp на прилагаемом к книге компакт-диске

В целом она напоминает аналогичную страницу аутентификации приложения покупателя, однако, есть и отличия.

Серверный сценарий получает идентификатор пользователя и пароль из полей формы с именами USR и PWD, записывая их в переменные sUser и sPassword, соответственно:

var sUser=Request("USR")(1);
var sPassword=Request("PWD")(1);

Вначале серверный сценарий устанавливаем соединение с источником данных:

var connect;
connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout = 10;
connect.Open("DSN=BookStore", "dbo", "");

Далее для выполнения аутентификации вызывается хранимая процедура ManagerLogin, работающая с таблицей managers:

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "ManagerLogin";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;
 
cmd.Parameters.Append(cmd.CreateParameter(
  "User", adVarChar, adParamInput, 50, sUser));
 
cmd.Parameters.Append(cmd.CreateParameter(
  "Pass", adVarChar, adParamInput, 50, sPassword));
 
var ParamOut = cmd.CreateParameter(
  "Rights", adVarChar, adParamOutput, 16, " ");
 
cmd.Parameters.Append(ParamOut);
cmd.Execute();

После выполнения этой процедуры результат аутентификации сохраняется в переменной ParamOut, а права сотрудника, пытающегося подключится к приложению, —в переменную сеанса Rights. Далее выполняется загрузка главной страницы административного приложения main.asp:

if(ParamOut.value!=" ")
{
  Session("Rights")=ParamOut.value;
  Session("Ok")="Ok";
  Session("UserID")=sUser;
  Response.Redirect("main.asp");
}

Если аутентификация закончилась с ошибкой, в окне приложения появляется сообщение Доступ запрещен, оформленное в виде ссылки на страницу аутентификации default.asp:

else
{
  Session("Ok")="";
  Session("UserID")="";
  Session("Rights")="";
%>
<HTML>
<BODY>
<CENTER><H1><a href=default.asp>
Доступ запрещен</a></H1></CENTER>
</BODY>
</HTML>
<%}%>

Главная страница

Главная страница административного приложения содержит определение двух фреймов (листинг 14-21).

Листинг 14-21. Вы найдете в файле chap14\BookShop\main.asp на прилагаемом к книге компакт-диске

В левом фрейме toc.asp находятся команды в виде ссылок на другие страницы,  а в правом (с именем main) отображается результаты выполнения этих команд:

<!-- #include file="header.asp" -->
. . .
<frameset cols="201,*">
  <frame name="contents" target="main" src="toc.asp">
  <frame name="main" src="hello.asp">
  <noframes>
  <body>
  <p>
Для просмотра этой страницы нужен браузер, способный работать с фреймами.</p>
  </body>
  </noframes>
</frameset>
. . .
<!-- #include file="footer.asp" -->

Обратите внимание на включение в исходный текст страницы файлов header.asp и footer.asp. Эти файлы такие же, как и в приложении покупателя. Они предназначены для проверки результата аутентификации и позволяют избежать прямой загрузки страниц приложения в обход аутентификации.

Страница меню команд

Исходный текст страницы команд toc.asp представлен в листинге 14-22.

Листинг 14-22. Вы найдете в файле chap14\BookShop\toc.asp на прилагаемом к книге компакт-диске

Для загрузки страниц ASP, выполняющих команды, мы применили здесь функцию клиентского сценария to, составленную на языке JavaScript:

<SCRIPT LANGUAGE=JavaScript>
function to(url)
{
  parent.main.document.location.href=
     url+"?"+Math.random().toString();
}
</SCRIPT>

Ее единственной задачей является отключение кэширования страниц браузером, что достигается добавлением к адресу URL загружаемой страницы фиктивного параметра в виде случайного числа. Этот механизм отключения кэширования мы рассматривали во второй главе нашей книги.

Для просмотра и редактирования списка управляющего персонала страница toc.asp загружает страницу managers.asp. Редактирование списка книг, имеющихся в продаже, выполняет страница books.asp, а работу со списком покупателей — страница CustomerSearch.asp:

<a href="javascript:to('managers.asp')">Управляющий персонал</a><br>
<a href="javascript:to('books.asp')">
Книги</a><br>
<a href="javascript:to('CustomerSearch.asp')">
Покупатели</a>

Страница с сообщением о подключении

При первой загрузке главной страницы административного приложения в окно правого фрейма загружается страница hello.asp, показанная в листинге 14-23.

Листинг 14-23. Вы найдете в файле chap14\BookShop\hello.asp на прилагаемом к книге компакт-диске

В ней содержится приветственное сообщение, включающее в себя идентификатор сотрудника, работающего с приложением, и его права. Эта информация, определяемая при аутентификации, извлекается из переменных сеанса с именами, соответственно, UserID и Rights:

<%
  var sRights="";
  if(Session("Rights") == "Administrator")
     sRights="Администратор";
  else if(Session("Rights") == "Sales_manager")
     sRights="Менеджер по продажам";
  else if(Session("Rights") == "sh_manager")
     sRights="Заведующий складом";
  else
     sRights=Session("Rights");
%>
<h2>Добро пожаловать, уважаемый <%=Session("UserID")%>!</h2>
<p>Вы подключились к системе как <b><%=sRights%></b>.

Страницы управления персоналом

С помощью страницы управления персоналом, расположенной в файле managers.asp, администратор магазина может управлять учетными записями сотрудников. Эта страница используется совместно с тремя другими — newmgr.asp, delmanager.asp и edtmanager.asp. Они выполняют, соответственно, создание, удаление и редактирование учетных записей.

Просмотр списка сотрудников

Просмотр списка сотрудников выполняется на странице managers.asp. Исходный текст этой страницы вы найдете в листинге 14-24.

Листинг 14-24. Вы найдете в файле chap14\BookShop\managers.asp на прилагаемом к книге компакт-диске

В начале своей работы сценарий, расположенный на странице managers.asp, запускает хранимую процедуру ListManagers:

var connect;
var rs;
connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

rs = Server.CreateObject("ADODB.Recordset")
rs.Open("ListManagers", connect,
     adOpenForwardOnly, adLockReadOnly, adCmdStoredProc);

Эта процедура не имеет никаких параметров, а в результате своей работы возвращает  содержимое полей Name, Rights и LastLogin всех записей файла managers. Эти поля сохраняются в наборе записей rs.

Далее сценарий проверяет наличие записей и, если файл managers не пуст, создает на их основе таблицу. Для этого в сценарии организован цикл:

<TABLE BORDER=1>
<TR><TH>Имя</TH><TH>Права</TH>
<TH>Время последнего подключения</TH><TH>Команды</TH></TR>
<%
if(rs.EOF)
{
%>
<TR><TD COLSPAN=4 ALIGN="CENTER">[Нет записей]</TD></TR>
<%
}
else
{
  var sID, sDate="";
  while (!rs.EOF)
  {
     sID=rs.Fields("Name").value;
     if(rs.Fields("LastLogin").value != null)
     {
       sDate=rs.Fields("LastLogin").value;
     }
 
     var sRights="";
     if(rs.Fields("Rights").value == "Administrator")
       sRights="Администратор";
     else if(rs.Fields("Rights").value == "Sales_manager")
       sRights="Менеджер по продажам";
     else if(rs.Fields("Rights").value == "sh_manager")
       sRights="Заведующий складом";
     else
       sRights=rs.Fields("Rights").value;
%>
<TR>
<TD><b><%=rs.Fields("Name").value%></b></TD>
<TD><%=sRights%></TD>
<TD>&nbsp;<%=sDate%></TD>
<TD>
<a href="edtmanager.asp?ID=<%=sID%>" target="main">Изменить</A>&nbsp;
<a href="delmanager.asp?ID=<%=sID%>" target="main">Удалить</A>
</TD>
</TR>
<%
     rs.MoveNext();
  }
  rs.Close();
  connect.Close();
}

В каждую строку создаваемой таблицы записывается идентификатор сотрудника, используемый им для подключения, его права, время последнего подключения, а также две команды — Изменить и Удалить.

Изменение учетной записи сотрудника выполняется на странице edtmanager.asp, а удаление — на странице delmanager.asp. И та, и другая страница получает в качестве параметра идентификатор пользователя ID, извлеченный из поля Name текущей строки обрабатываемого набора записей rs.

В последнюю строку таблицы сценарий вставляет ссылку Новый сотрудник, отправляющую администратора на страницу newmgr.asp. Там он сможет создать учетную запись для нового сотрудника:

<TR><TD COLSPAN=6 ALIGN="CENTER"><a href="newmgr.asp" target="main">[Новый сотрудник]</a></TD></TR>

Исходный текст хранимо процедуры ListManagers, с помощью которой сценарий managers.asp получает список сотрудников, представлен в листинге 14-25.

Листинг 14-25. Вы найдете в файле chap14\BookShopScripts\dbo.ListManagers.PRC на прилагаемом к книге компакт-диске

Эта процедура получает содержимое полей Name, Rights и LastLogin таблицы managers при помощи оператора SELECT и не имеет никаких интересных особенностей:

CREATE PROCEDURE ListManagers  AS
SELECT Name, Rights, LastLogin
FROM managers

Создание новой записи

Для создания новой учетной записи сотрудника магазина вызывается страница newmgr.asp, исходный текст которой приведен в листинге 14-26.

Листинг 14-26. Вы найдете в файле chap14\BookShop\newmgr.asp на прилагаемом к книге компакт-диске

На этой странице имеется форма, позволяющая ввести имя и  пароль нового сотрудника, а также выбрать его права из списка:

<form ACTION="createmgr.asp" METHOD="post">
  <h1>
Новый администратор</h1>
  <table BORDER="0" CELLPADDING="5" CELLSPACING="0">
     <tr><td>
Имя</td><td>
      
<input SIZE="16" TYPE="EDIT" NAME="USR">
    
</td></tr><tr>
     <td>
Пароль </td> <td>
      
<input SIZE="16" TYPE="EDIT" NAME="PWD"> </td>
     </tr><tr> <td>
Права</td> <td>
      
<select NAME="RG" size="1">
       <option selected value="Administrator">
Все права</option>
       <option value="Sales_manager">
Менеджер по продажам</option>
       <option value="sh_manager">
Заведующий складом</option>
       </select></td>   </tr>
     <tr><td>&nbsp; </td><td>

      
<input TYPE="submit" VALUE="Создать"> </td>
     </tr>
  </table>

</form>  

В зависимости от структурной организации своей фирмы Вы можете выбрать различный набор прав, отредактировав набор тегов <OPTION> в списке <SELECTION>.

Щелчок кнопки Создать отправляет данные, подготовленный в полях формы, на страницу createmgr.asp (листинг 14-27). Расположенный там серверный сценарий добавляет нового сотрудника в таблицу managers базы данных магазина.

Листинг 14-27. Вы найдете в файле chap14\BookShop\createmgr.asp на прилагаемом к книге компакт-диске

Добавление новых сотрудников разрешено только администраторам, поэтому в начале своей работы сценарий страницы createmgr.asp проверяет права пользователя, записанные в переменную сеанса с именем Rights при аутентификации. Если это администратор, сценарий продолжает свою работу, а если нет, — выводит сообщение о недостаточных правах:

if(Session("Rights")=="Administrator")
{
  connect = Server.CreateObject("ADODB.Connection");
  connect.ConnectionTimeout = 15;
  connect.CommandTimeout =  10;
  connect.Open("DSN=BookStore", "dbo", "");

  var cmd = Server.CreateObject("ADODB.Command");
  cmd.CommandText = "NewMgr";
  cmd.CommandType = adCmdStoredProc;
  cmd.ActiveConnection = connect;
 
  cmd.Parameters.Append(cmd.CreateParameter(
     "User", adVarChar, adParamInput, 50, Request("USR")(1)));
    
  cmd.Parameters.Append(cmd.CreateParameter(
     "Pwd", adVarChar, adParamInput, 50, Request("PWD")(1)));
      
  cmd.Parameters.Append(cmd.CreateParameter(
     "Rights", adVarChar, adParamInput, 16, Request("RG")(1)));
      
  cmd.Execute();

 
connect.Close();
}
else
{
  Response.Redirect("error.asp?ERROR=
Недостаточные права");
}

Далее сценарий соединяется с базой данных и запускает хранимую процедуру NewMgr, создающую новую запись в таблице managers. Этой процедуре передаются три входных параметра, значение которых получено из полей формы создания учетной записи нового сотрудника, рассмотренной нами ранее.

После завершения своей работы сценарий страницы createmgr.asp снова загружает в правый фрейм главной страницы административного приложения документ managers.asp:

Response.Redirect("managers.asp");

Теперь в нем появится новая только что добавленная запись.

Исходный текст хранимой процедуры NewMgr Вы найдете в листинге 14-28.

Листинг 14-28. Вы найдете в файле chap14\BookShopScripts\dbo.NewMgr.PRC на прилагаемом к книге компакт-диске

Она просто вставляет значения, полученные через параметры @User, @Pass и @Rights в соответствующие поля таблицы managers:

CREATE PROCEDURE NewMgr @User varchar(50), @Pass varchar(50),
 
@Rights varchar(16) AS
INSERT managers (Name, Password, Rights, LastLogin)

VALUES(@User, @Pass, @Rights, NULL)

Что же касается поля LastLogin, хранящего дату последнего подключения сотрудника к системе, то в нее записывается значение NULL. Мы это делаем потому, что только что зарегистрированный сотрудник еще ни разу не входил в систему.

Удаление учетной записи сотрудника

Эта операция выполняется на странице delmanager.asp (листинг 14-29).

Листинг 14-29. Вы найдете в файле chap14\ BookShop\delmanager.asp на прилагаемом к книге компакт-диске

После проверки прав текущего пользователя серверный сценарий, расположенный на этой странице, получает со страницы managers.asp идентификатор удаляемой записи через параметр ID и запускает хранимую процедуру DelMgr:

var rs, connect;
if(Session("Rights")=="Administrator")
{
  try
  {
     connect = Server.CreateObject("ADODB.Connection");
     connect.ConnectionTimeout = 15;
     connect.CommandTimeout =  10;
     connect.Open("DSN=BookStore", "dbo", "");

     var cmd = Server.CreateObject("ADODB.Command");
     cmd.CommandText = "DelMgr";
     cmd.CommandType = adCmdStoredProc;
     cmd.ActiveConnection = connect;
 
     cmd.Parameters.Append(cmd.CreateParameter(
       "User", adVarChar, adParamInput, 50, Request("ID")(1)));

     cmd.Execute();
     connect.Close();
  }
  catch (ex)
  {

     . . .

  }
  Response.Redirect("managers.asp");
}
else
{
  Response.Redirect("error.asp?ERROR=0&ERRMSG=
Недостаточные права");
}

Процедуре DelMgr (листинг 14-30) этот идентификатор передается через параметр с именем User.

Листинг 14-30. Вы найдете в файле chap14\BookShopScripts\dbo.DelMgr.PRC на прилагаемом к книге компакт-диске

В случае успешного завершения в правый фрейм главного окна административного приложения вновь загружается страница managers.asp.

Хранимая процедура DelMgr удаляет из файла managers запись сотрудника, идентификатор которого равен идентификатору, полученному процедуре через параметр @User:

CREATE PROCEDURE DelMgr @User varchar(50) AS
DELETE managers WHERE Name=@User

Редактирование записи сотрудника

Редактирование записи сотрудника выполняется на странице edtmanager.asp (листинг 14-31).

Листинг 14-31. Вы найдете в файле chap14\ BookShop\edtmanager.asp на прилагаемом к книге компакт-диске

Операция редактирования учетных записей сотрудников должна выполняться только администраторами, поэтому прежде чем обращаться к базе данных, мы проверяем содержимое переменной сеанса Rights.

Если с правами все в порядке, запускается на выполнение хранимая процедура GetMgr, извлекающая текущие параметры учетной записи выбранного сотрудника. Она имеет один входной параметр User (идентификатор сотрудника) и два выходных — Pwd (пароль) и Rights (права сотрудника):

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "GetMgr";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;

var Usr=cmd.CreateParameter(

 
"User", adVarChar, adParamInput, 50, Request("ID")(1));

var Pwd=cmd.CreateParameter(
  "Pwd", adVarChar, adParamOutput, 50,  " ");

var Rights=cmd.CreateParameter(
  "Rights", adVarChar, adParamOutput, 16, " ");
 
cmd.Parameters.Append(Usr);
cmd.Parameters.Append(Pwd);
cmd.Parameters.Append(Rights);
cmd.Execute();
connect.Close();

Значения, извлеченные из таблицы managers, помещаются в форму редактирования, с помощью которой администратор может их изменить:

<FORM ACTION="updatemgr.asp" METHOD="POST">
<H2>
Редактирование записи пользователя <%=Usr.Value%></H2>
<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=0>
<TR><TD>
Имя</TD><TD>
  <INPUT SIZE=16 TYPE="HIDDEN" NAME="ID" VALUE="<%=Usr.Value%>">
  <INPUT SIZE=16 TYPE="EDIT" NAME="USR" VALUE="<%=Usr.Value%>">
</TD></TR><TR><TD>
Пароль</TD><TD>
  <INPUT SIZE=16 TYPE="EDIT" NAME="PWD" VALUE="<%=Pwd.Value%>">
</TD></TR>
<tr><td>
Права </td>
<%
var sAdm="", sSMan="", sStH="";
if(Rights.Value == "Administrator")
  sAdm="selected";
else if(Rights.Value == "Sales_manager")
  sSMan="selected";
else if(Rights.Value == "sh_manager")
  sStH="selected";
%>
<td>
<select NAME="RG" size="1">
  <option <%=sAdm%> value="Administrator">
Все права</option>
  <option <%=sSMan%> value="Sales_manager">
Менеджер по продажам</option>
  <option <%=sStH%>  value="sh_manager">
Заведующий складом</option>
</select> </td></tr>
<TR><TD>&nbsp;</TD><TD>
<INPUT TYPE="SUBMIT" VALUE="
Сохранить изменения"></TD></TR>
</TABLE></FORM>

После щелчка кнопки Сохранить изменения управление передается странице сценария updatemgr.asp (листинг 14-32), выполняющей обновление записи в файле managers.

Запуская страницу updatemgr.asp, наш сценарий передает ей параметры ID (идентификатор записи сотрудника), USR (идентификатор сотрудника), PWD (пароль) и RG (права сотрудника), причем параметр ID передается через скрытое поле формы.

Листинг 14-32. Вы найдете в файле chap14\ BookShop\updatemgr.asp на прилагаемом к книге компакт-диске

Задача сценария, расположенного на странице updatemgr.asp, заключается в запуске хранимой процедуры SetMgr, выполняющей обновление файла managres. Данные для обновления она получает через свои параметры @User, @NewUser, @Pass и @Rights:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");
    
var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "SetMgr";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;

var Usr=cmd.CreateParameter(
  "User", adVarChar, adParamInput, 50, Request("ID")(1));
      
var NewUsr=cmd.CreateParameter(
  "NewUser", adVarChar, adParamInput, 50, Request("USR")(1));
      
var Pwd=cmd.CreateParameter(
  "Pwd", adVarChar, adParamInput, 50, Request("PWD")(1));
      
var Rights=cmd.CreateParameter(
  "Rights", adVarChar, adParamInput, 16, Request("RG")(1));
      
cmd.Parameters.Append(Usr);
cmd.Parameters.Append(NewUsr);
cmd.Parameters.Append(Pwd);
cmd.Parameters.Append(Rights);
cmd.Execute();
connect.Close();

Исходный текст процедуры SetMgr находится в листинге 14-33.

Листинг 14-33. Вы найдете в файле chap14\BookShopScripts\dbo.SetMgr.PRC на прилагаемом к книге компакт-диске

Она выполняет обновление полей записи файла managers значениями, полученными через параметры:

CREATE PROCEDURE SetMgr @User varchar(50), @NewUser varchar(50) , @Pass varchar(50) , @Rights varchar(16) AS
UPDATE managers SET Name=@NewUser, Rights=@Rights, Password=@Pass FROM managers WHERE Name=@User

Описанную схему редактирования записей таблицы managers Вы можете применить для создания редакторов любых других таблиц, как отдельных, так и связанных между собой.

Редактирование списка книг

Сотрудника Вашего магазина должны иметь возможность просматривать и редактировать список книг, имеющихся в продаже, а также описания этих книг. Эти задачи решаются с помощью серверных сценариев books.asp, newbook.asp, createbook.asp, delbook.asp, editbook.asp и updatebook.asp.

Просмотр списка книг

Для просмотра списка книг используется страница books.asp, исходный текст которой расположен в листинге 14-34.

Листинг 14-34. Вы найдете в файле chap14\ BookShop\books.asp на прилагаемом к книге компакт-диске

Для получения списка всех книг сценарий вызывает хранимую процедуру ListBooks:

var connect;
var rs;
connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

rs = Server.CreateObject("ADODB.Recordset")
rs.Open("ListBooks", connect,
  adOpenForwardOnly, adLockReadOnly, adCmdStoredProc);

Если список пуст, вместо таблицы со списком книг отображается строка «Нет записей». В противном случае сценарий формирует таблицу с описанием книг, обрабатывая в цикле набор записей rs, полученный в результате работы процедуры ListBooks:

if(rs.EOF)
{
%>
<TR><TD COLSPAN=4 ALIGN="CENTER">[Нет записей]</TD></TR>
<%
}
else
{
%>
<HTML>
<BODY>
<h2>Список книг</h2>
<TABLE BORDER=1>
<tr><th>Книга</th><th>Команда</th></tr>
<%
  var i=0, sID, sDate="";
  while (!rs.EOF)
  {
%>
<tr><td><b><%=rs.Fields("Author")%>
<br><%=rs.Fields("Title")%></b><br><i><%=rs.Fields("Publisher")%></i>
<br>Цена: <%=rs.Fields("Price")%> у.е.
<br>Дата обновления: <%=rs.Fields("AddDate")%></td>
<td>
<a href="editbook.asp?ID=<%=rs.Fields("booksID")%>" target="main">Изменить</A>&nbsp;
<a href="delbook.asp?ID=<%=rs.Fields("booksID")%>" target="main">Удалить</A>
</td><tr>
<tr><td colspan=2>Аннотация:<br><small><%=rs.Fields("Annotation")%></small></td><tr>
<%
     rs.MoveNext();
  }
  rs.Close();
}
connect.Close();

В каждую строку создаваемой таблицы вставляются ссылки на страницы изменения описания книги и ее удаления. Первая задача выполняется страницей editbook.asp, а вторая — страницей delbook.asp.

В нижней строке таблицы размещается ссылка Новая книга:

<a href="newbook.asp" target="main">[Новая книга]</a>

Если ее щелкнуть, загружается страница newbook.asp. Эта страница предназначена для добавления в базу данных описания новой книги.

Что же касается хранимой процедуры ListBooks (листинг 14-35), то ее задачей является выборка полей booksID, Author, Title, Publisher, Price, AddDate и Annotation из таблицы books.

Листинг 14-35. Вы найдете в файле chap14\BookShopScripts\dbo.ListBooks.PRC на прилагаемом к книге компакт-диске

Эта задача решается с помощью простого оператора SELECT:

CREATE PROCEDURE ListBooks  AS
SELECT booksID,Author, Title, Publisher, Price, AddDate,Annotation
FROM books

Добавление новой книги

Как мы только что сказали, после щелчка ссылки Новая книга управление передается странице newbook.asp (листинг 14-36).

Листинг 14-36. Вы найдете в файле chap14\ BookShop\newbook.asp на прилагаемом к книге компакт-диске

Она содержит форму с полями описания книги:

<form ACTION="createbook.asp" METHOD="post">
  <h2>
Новая книга</h2>
  <table BORDER="0" CELLPADDING="5" CELLSPACING="0">
     <tr><td ALIGN="left" VALIGN="top">
Автор </td>
          <td ALIGN="left" VALIGN="top">

    
<input type="text" name="Author" size="50"> </td>
       </tr><tr><td ALIGN="left" VALIGN="top">
Название </td>
          <td ALIGN="left" VALIGN="top">

    
<textarea rows="2" name="Title" cols="50"></textarea> </td>
       </tr><tr><td ALIGN="left" VALIGN="top">
Издатель</td>
          <td ALIGN="left" VALIGN="top">

    
<select name="Publisher" size="1">
       <option value="
Русская редакция">Русская редакция</option>
       <option value="
Диалог-МИФИ">Диалог-МИФИ</option>
       <option value="
Бином">Бином</option>
       <option value="Microsoft Press">Microsoft Press</option>
     </select></td>   </tr><tr>
          <td ALIGN="left" VALIGN="top">
Цена, у.е.</td>
          <td ALIGN="left" VALIGN="top">

    
<input type="text" name="Price" size="20"></td>
       </tr><tr><td ALIGN="left" VALIGN="top">
Аннотация</td>
          <td ALIGN="left" VALIGN="top">

    
<textarea rows="5" name="Annotation" cols="50">
    
</textarea></td></tr><tr>
          <td ALIGN="left" VALIGN="top">&nbsp; </td>
          <td ALIGN="left" VALIGN="top">

    
<input TYPE="submit" VALUE="Добавить"> </td></tr>
  </table>
</form>  

После заполнения всех полей формы сотрудник магазина должен щелкнуть кнопку Добавить, в результате чего данные из полей формы будут переданы сценарию createbook.asp (листинг 14-37).

Листинг 14-37. Вы найдете в файле chap14\ BookShop\createbook.asp на прилагаемом к книге компакт-диске

Задачей этого сценария является получение указанных выше данных через параметры Author, Title, Publisher, Price и Annotation, с последующей записью в таблицу books.

Запись сведений о новой книге выполняется хранимой процедурой NewBook с применением уже знакомой Вам техники:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "NewBook";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;
 
cmd.Parameters.Append(cmd.CreateParameter(
  "Author", adVarChar, adParamInput, 50, Request("Author")(1)));
      
cmd.Parameters.Append(cmd.CreateParameter(
  "Title", adVarChar, adParamInput, 200, Request("Title")(1)));
      
cmd.Parameters.Append(cmd.CreateParameter(
  "Publisher", adVarChar, adParamInput, 50,
   Request("Publisher")(1)));
      
cmd.Parameters.Append(cmd.CreateParameter(
  "Price", adCurrency, adParamInput, 50, Request("Price")(1)));
      
cmd.Parameters.Append(cmd.CreateParameter(
  "Annotation", adVarChar, adParamInput, 2048,
  Request("Annotation")(1)));
      
cmd.Execute();
connect.Close();

Исходный текст хранимой процедуры NewBook приведен в листинге 14-38.

Листинг 14-38. Вы найдете в файле chap14\BookShopScripts\dbo.NewBook.PRC на прилагаемом к книге компакт-диске

Хранимая процедура NewBook имеет одну особенность — она записывает аннотацию к книге в  поле Annotation, имеющее длину 2048 байт:

CREATE PROCEDURE NewBook @Author varchar(50), @Title varchar(200), @Publisher varchar(50), @Price money, @Annotation varchar(2048) AS
INSERT books (Author, Title, Publisher, Price,
Annotation) VALUES(@Author, @Title, @Publisher, @Price, @Annotation)

Такая большая длина поля может быть только в таблицах SQL Server версии 7.0. Что же касается версии 6.5, то для нее длина поля ограничена величиной 255 байт, поэтому хранение больших объемов текста нужно выполнять по-другому (например, с использованием полей типа text).

Удаление книги

Если сотрудник магазина захочет удалить книгу из базы данных и щелкнет ссылку Удалить в списке книг, управление получит страница delbook.asp (листинг 14-39).

Листинг 14-39. Вы найдете в файле chap14\ BookShop\delbook.asp на прилагаемом к книге компакт-диске

Данная страница запускает хранимую процедуру DelBook, передавая ей в качестве единственного параметра идентификатор удаляемой книги bookID:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");
var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "DelBook";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;
 
cmd.Parameters.Append(cmd.CreateParameter(
  "bookID", adVarChar, adParamInput, 50, Request("ID")(1)));
cmd.Execute();
connect.Close();

Этот идентификатор извлекается из параметра запуска страницы с именем ID.

Исходный текст хранимой процедуры DelBook Вы найдете в листинге 14-40.

Листинг 14-40. Вы найдете в файле chap14\BookShopScripts\dbo.DelBook.PRC на прилагаемом к книге компакт-диске

Эта процедура удаляет из файла books записи с идентификатором, полученным ей через параметр @bookID:

CREATE PROCEDURE DelBook @bookID varchar(50) AS
DELETE books WHERE booksID=@bookID

Редактирование описания книги

Процесс редактирования описания книги состоит из двух шагов. На первом шаге мы получаем сведения о книге из таблицы books и записываем их в поля формы для редактирования, а на втором получаем отредактированное описание книги и записываем его обратно в таблицу books.

Первый шаг выполняется при помощи сценария editbook.asp (листинг 14-41).

Листинг 14-41. Вы найдете в файле chap14\ BookShop\editbook.asp на прилагаемом к книге компакт-диске

После проверки прав пользователя сценарий запускает хранимую процедуру GetBook, определяя для нее один входной и несколько выходных параметров:

var rs, connect;
connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "GetBook";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;

var bookID=cmd.CreateParameter(
  "bookID", adVarChar, adParamInput, 50, Request("ID")(1));
      
var Author=cmd.CreateParameter(
  "Author", adVarChar, adParamOutput, 50, " ");
      
var Title=cmd.CreateParameter(
  "Title", adVarChar, adParamOutput, 200, " ");
      
var Publisher=cmd.CreateParameter(
  "Publisher", adVarChar, adParamOutput, 50, " ");
      
var Price=0;
Price=cmd.CreateParameter(
  "Price", adCurrency, adParamOutput, 8, 0);
      
var AddDate=cmd.CreateParameter(
  "AddDate", adVarChar, adParamOutput, 50, " ");
      
var Annotation=cmd.CreateParameter(
  "Annotation", adVarChar, adParamOutput, 2048, " ");
 
cmd.Parameters.Append(bookID);
cmd.Parameters.Append(Author);
cmd.Parameters.Append(Title);
cmd.Parameters.Append(Publisher);
cmd.Parameters.Append(Price);
cmd.Parameters.Append(AddDate);
cmd.Parameters.Append(Annotation);
cmd.Execute();

Значения выходных параметров, полученные в результате работы хранимой процедуры, записываются в поля формы, предназначенной для редактирования сведений о книге:

<FORM ACTION="updatebook.asp" METHOD="POST">
<H2>Редактирование сведений о книге</H2>
<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=0>
<tr>
  <td ALIGN="left" VALIGN="top"><b>Автор</b></td>
  <td ALIGN="left" VALIGN="top">
<input type="text" name="Author" size="50" value="<%=Author.Value%>"> </td></tr><tr>
  <td ALIGN="left" VALIGN="top"><b>Название</b></td>
  <td ALIGN="left" VALIGN="top">
<textarea rows="2" name="Title" cols="50"><%=Title.Value%></textarea> </td></tr><tr>
  <td ALIGN="left" VALIGN="top"><b>Издатель</b></td>
  <td ALIGN="left" VALIGN="top">
<%
var s1="", s2="", s3="", s4="";
if(Publisher.Value == "Русская редакция")
  s1="selected";
else if(Publisher.Value == "Диалог-МИФИ")
  s2="selected";
else if(Publisher.Value == "Бином")
  s3="selected";
else if(Publisher.Value == "Microsoft Press")
  s4="selected";
%>
<select name="Publisher" size="1">
<option <%=s1%> value="Русская редакция">Русская редакция</option>
<option <%=s2%> value="Диалог-МИФИ">Диалог-МИФИ</option>
<option <%=s3%> value="Бином">Бином</option>
<option <%=s4%> value="Microsoft Press">Microsoft Press</option>
</select></td>
</tr><tr>
  <td ALIGN="left" VALIGN="top"><b>Цена, у.е.</b></td>
  <td ALIGN="left" VALIGN="top">
<input type="text" name="Price" size="20" value="<%=Price.Value%>">
  </td></tr><tr>
  <td ALIGN="left" VALIGN="top"><b>Аннотация</b></td>
  <td ALIGN="left" VALIGN="top">
<textarea rows="5" name="Annotation" cols="50"><%=Annotation.Value%>
</textarea></td></tr>
<TR><TD>&nbsp;</TD><TD>
<INPUT TYPE="hidden" VALUE="<%=bookID%>" name="bookID">
<INPUT TYPE="SUBMIT" VALUE="Сохранить изменения"></TD></TR>
</TABLE></FORM>

После щелчка кнопки Сохранить изменения данные из этой формы передаются странице updatebook.asp, которую мы рассмотрим ниже.

Сведения о книге извлекаются из базы данных при помощи хранимой процедуры GetBook (листинг 14-42).

Листинг 14-42. Вы найдете в файле chap14\BookShopScripts\dbo.GetBook.PRC на прилагаемом к книге компакт-диске

Эта процедура принимает в качестве входного параметра идентификатор книги @bookID, возвращая информацию о ней через выходные параметры:

CREATE PROCEDURE GetBook @bookID varchar(50), @Author varchar(50) output, @Titile varchar(200) output, @Publisher varchar(50) output, @Price money output, @AddDate datetime output, @Annotation varchar(2048) output AS

SELECT @Author=Author, @Titile=Title, @Publisher=Publisher, @Price=Price, @AddDate=AddDate, @Annotation=Annotation 

FROM books
WHERE booksID=@bookID

Обновление отредактированного описания книги в таблице books выполняется серверным сценарием, расположенным на странице updatebook.asp (листинг 14-43).

Листинг 14-43. Вы найдете в файле chap14\ BookShop\updatebook.asp на прилагаемом к книге компакт-диске

Эта страница вызывает хранимую процедуру SetBook, обновляющую поля таблицы books:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "SetBook";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;

var bookID=cmd.CreateParameter(
  "bookID", adVarChar, adParamInput, 50, Request("bookID")(1));
      
var Author=cmd.CreateParameter(
  "Author", adVarChar, adParamInput, 50, Request("Author")(1));
      
var Title=cmd.CreateParameter(
  "Title", adVarChar, adParamInput, 200, Request("Title")(1));
      
var Publisher=cmd.CreateParameter(
  "Publisher", adVarChar, adParamInput, 50,
  Request("Publisher")(1));
      
var Price=cmd.CreateParameter(
  "Price", adVarChar, adParamInput, 50, Request("Price")(1));
      
var Annotation=cmd.CreateParameter(
  "Annotation", adVarChar, adParamInput, 2048,
   Request("Annotation")(1));
    
cmd.Parameters.Append(bookID);
cmd.Parameters.Append(Author);
cmd.Parameters.Append(Title);
cmd.Parameters.Append(Publisher);
cmd.Parameters.Append(Price);
cmd.Parameters.Append(Annotation);
cmd.Execute();
connect.Close();

Исходный текст процедуры приведен в листинге 14-44.

Листинг 14-44. Вы найдете в файле chap14\BookShopScripts\dbo.SetBook.PRC на прилагаемом к книге компакт-диске

Процедура выполняет обновление полей файла books значениями, переданными ей через параметры:

CREATE PROCEDURE SetBook @bookID varchar(50), @Author varchar(50), @Title varchar(200), @Publisher varchar(50), @Price varchar(50), @Annotation varchar(2048) AS

UPDATE books SET Author=@Author, Title=@Title, Publisher=@Publisher, Price=CONVERT(money, @Price), Annotation=@Annotation
FROM books WHERE booksID=@bookID

Работа с записями покупателей

Администратор нашего Интернет-магазина выполняет с помощью административного приложения просмотр списка зарегистрированных покупателей, просмотр содержимого их корзин и удаление учетных записей неактивных покупателей.

Форма поиска покупателей

Так как зарегистрированных покупателей в популярном магазине может быть очень много, едва ли имеет смысл выводить их полный список для просмотра или редактирования отдельных учетных записей. Вместо этого мы разработали поисковую систему, с помощью которой сотрудник магазина сможет находить учетные записи пользователей по их именам, адресам E-Mail или датам регистрации. Дополнительно мы предусмотрели использование при поиске символов шаблонов, необходимых для того, чтобы найти пользователей по неточным или неполным именам или адресам электронной почты.

Исходный текст страницы CustomerSearch.asp, предназначенной для задания параметров поиска, представлен в листинге 14-45.

Листинг 14-45. Вы найдете в файле chap14\ BookShop\CustomerSearch.asp на прилагаемом к книге компакт-диске

Обратите внимание на то, что в этой странице мы используем одновременно и клиентские, и серверные сценарии. Для выбора посетителей по дате регистрации мы включили в исходный текст страницы файл calendar.js, рассмотренный нами ранее во второй главе. С помощью средств Dynamic HTML этот файл создает на странице два календаря, предназначенных для указания начальной и конечной даты регистрации.

Срезу после загрузки страницы, однако, в дело включается серверный сценарий. Анализируя содержимое переменной сеанса SearchUsersFirstUse, серверный сценарий выбирает для инициализации календаря одну из двух функций клиентского сценария: buildmap или buildmapEx:

<%
if(Session("SearchUsersFirstUse") == null)
{
%>
<body onload="buildmap()">
<%
}
else
{
  dDateCheck=Session("dSearchUsersDateCheck");
  dLogName=Session("dSearchUsersLogName");
  dEMail=Session("dSearchUsersEMail");
%>
<body onload="buildmapEx(<%=Session("dSearchUsersFromFY")%>,
<%=Session("dSearchUsersFromFM")%>, <%=Session("dSearchUsersFromFD")%>,
<%=Session("dSearchUsersToTY")%>,
<%=Session("dSearchUsersToTM")%>, <%=Session("dSearchUsersToTD")%>,
'<%=(dLogName == "") ? '' : dLogName%>',
'<%=(dEMail == "") ? '': dEMail%>',
'<%=dDateCheck%>')">
<%
}%>

Функция buildmap изображает на странице календари, задающие период времени по умолчанию (длительностью в одну неделю).

Для того чтобы не заставлять пользователя вводить один и тот же диапазон дат, серверный сценарий запоминает этот диапазон в переменных сеанса. Когда страница CustomerSearch.asp загружается во второй раз, эти параметры извлекаются из переменных сеанса, и затем подставляются в качестве параметров функции клиентского сценария buildmapEx.

Переменная сеанса dSearchUsersDateCheck хранит флаг поиска по диапазону дат, а переменные dSearchUsersLogName и dSearchUsersEMail — имя и адрес E-Mail посетителя. В переменных сеанса dSearchUsersFromFY, dSearchUsersFromFM и dSearchUsersFromFD находятся компоненты начальной даты регистрации посетителя, а в переменных dSearchUsersToFY, dSearchUsersToFM и dSearchUsersToFD — компоненты конечной даты регистрации посетителя.

На странице CustomerSearch.asp находится также функция клиентского сценария с именем go:

function go()
{
var sLogName=escape(document.all.SearchForm.LogName.value);
var sEMail=escape(document.all.SearchForm.CEMail.value);

var sUseDataCheckBox="";
if(document.all.UseDataCheckBox.checked)
{
  sUseDataCheckBox="yes";
}
else
{
  sUseDataCheckBox="no";
}

window.location.href="GetSearchResults.asp?DATECHECK="+
  sUseDataCheckBox+
  "&FY="+byear.toString()+"&FM="+bmonth.toString()+
  "&FD="+bday.toString()+
  "&TY="+eyear.toString()+"&TM="+emonth.toString()+
  "&TD="+eday.toString()+ "&MODE=first"+
  "&LOGNAME="+sLogName+"&EMAIL="+sEMail+
  "&FRCE="+Math.random().toString();
}

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

Обратите внимание, как функция go выполняет кодирование шаблона имени и адреса электронной почты, вызывая встроенную функцию JavaScript с именем escape:

var sLogName=escape(document.all.SearchForm.LogName.value);
var sEMail=escape(document.all.SearchForm.CEMail.value);

Такая кодировка необходима для правильной передаче вызываемой странице ASP параметров с символами кириллицы и другими «особыми» символами, такими как символы пунктуации.

Для загрузки в правый фрейм страницы GetSearchResults.asp, выполняющей поиск регистрационных записей в базе данных функция go использует свойство браузера window.location.href. Обратите внимание на фиктивный параметр FRCE, предназначенный для отключения кэширования методом генерации случайного адреса URL.

Работу функции клиентского сценария hidecalendar мы уже рассматривали ранее во второй главе. Она предназначена для удаления календарей из страницы при снятии отметки с переключателя искать по дате регистрации:.

Просмотр списка зарегистрированных покупателей

Рассмотрим исходный текст страницы GetSearchResults.asp, выполняющей поиск учетных записей посетителей магазина в базе данных. Вы найдете его в листинге 14-46.

Листинг 14-46. Вы найдете в файле chap14\ BookShop\GetSearchResults.asp на прилагаемом к книге компакт-диске

Так же как и только что рассмотренная страница CustomerSearch.asp, страница GetSearchResults.asp использует одновременно клиентские и серверные сценарии. В частности, функция клиентского сценария trydeluser применяется при удалении ненужной учетной записи неактивного посетителя:

<SCRIPT LANGUAGE=javascript>
<!--
function trydeluser(sUserID, sUserLogin)
{
  var vParm;
  var rVal;
  vParm=new Array(2);
  vParm[0]=sUserID;
  vParm[1]=sUserLogin;
  rVal=showModalDialog("trydeleteuserdlg.asp", vParm, "dialogHeight:160px;dialogWidth:350px;status:0");
  if(rVal==false) return;
 
  // Удаление записи
  var sASP="";
  sASP="trydeleteacc.asp?ID=" + sUserID;
  rVal=showModalDialog(sASP, vParm, "dialogHeight:160px;dialogWidth:350px;status:0");
  if(rVal==false) return;
 
  // Удаление строки из таблицы
  sNode="A"+sUserID;
  var oDeletedRow=document.getElementById(sNode);
  oDeletedRow.removeNode(true);
}

//-->
</SCRIPT>

Когда страница GetSearchResults.asp получает управление в первый раз, расположенный на ней серверный сценарий записывает в переменную сеанса с именем SearchUsersFirstUse строку «used»:

Session("SearchUsersFirstUse")="used";

Далее сценарий вызывает хранимую процедуру SearchUsers, возвращающую список найденных учетных записей посетителей:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "SearchUsers";
cmd.CommandType = 4;
cmd.ActiveConnection = connect;

var dFrom, dTo, dLogName, dName, dEMail, dDateCheck;

// После обновления записи
if(Request("MODE")(1) == "restart")
{
  dFrom=Session("dSearchUsersFrom");
  dTo=Session("dSearchUsersTo");
  dLogName=Session("dSearchUsersLogName");
  dEMail=Session("dSearchUsersEMail");
  dDateCheck=Session("dSearchUsersDateCheck");
}
 
// После страницы поиска
else
{
  dFrom=trim(Request("FY")(1), 4)+trim(Request("FM")(1), 2)
     +trim(Request("FD")(1), 2);
  Session("dSearchUsersFrom")=dFrom;
  Session("dSearchUsersFromFY")=trim(Request("FY")(1), 4);
  Session("dSearchUsersFromFM")=trim(Request("FM")(1), 2);
  Session("dSearchUsersFromFD")=trim(Request("FD")(1), 2);

  dTo=trim(Request("TY")(1), 4)+trim(Request("TM")(1),2)
     +trim(Request("TD")(1), 2);
  Session("dSearchUsersTo")=dTo;
  Session("dSearchUsersToTY")=trim(Request("TY")(1), 4);
  Session("dSearchUsersToTM")=trim(Request("TM")(1), 2);
  Session("dSearchUsersToTD")=trim(Request("TD")(1), 2);

  dDateCheck=Request("DATECHECK")(1);
  Session("dSearchUsersDateCheck")=dDateCheck;

  dLogName=Request("LOGNAME")(1);
  if(dLogName == "")
     dLogName="%";
  Session("dSearchUsersLogName")=dLogName;

  dEMail=Request("EMAIL")(1);
  if(dEMail == "")
     dEMail="%";
  Session("dSearchUsersEMail")=dEMail;
}

cmd.Parameters.Append(cmd.CreateParameter("From", 200, 1, 13,
  dFrom));
cmd.Parameters.Append(cmd.CreateParameter("To", 200, 1, 13, dTo));
cmd.Parameters.Append(cmd.CreateParameter("Login", 200, 1, 20,
  dLogName));
cmd.Parameters.Append(cmd.CreateParameter("Email", 200, 1, 80,
  dEMail));
cmd.Parameters.Append(cmd.CreateParameter("DateCheck", 200, 1, 20,
  dDateCheck));

rs = cmd.Execute();

В зависимости от того, попали ли мы на страницу GetSearchResults.asp после обновления учетной записи или со страницы поиска этих записей, выполняется извлечение параметров поиска из переменных сеанса или запись их в эти переменные, соответственно. Все это делается для того, чтобы пользователь мог повторно не вводить параметры поиска, если ему потребовалось их изменить.

Далее параметры поиска передаются хранимой процедуре SearchUsers, выполняющей запрос к базе данных. Результаты этого запроса получаются в виде набора записей rs.

На следующем этапе серверный сценарий страницы GetSearchResults.asp формирует документ HTML, записывая в него параметры поиска и таблицу с найденными учетными записями. При этом в локальной переменной nCounter подсчитывается общее количество найденных покупателей, а в переменной nSumm выполняется подсчет общего количества денег полученных от найденных покупателей:

<h2>Покупатели</h2>
<%if(Session("dSearchUsersDateCheck") == "yes")
{%>
<p>Зарегистрировались в период от <b><%=dFrom%></b> до <b><%=dTo%></b>
<%} else { %>
<p>Зарегистрировались в любое время
<%}%>
<br>Идентификатор: <b><%=(dLogName != "") ? dLogName : "[любой]"%></b>,
EMail: <b><%=(dEMail != "") ? dEMail : "[любой]"%></b></p>
<TABLE BORDER=1>
<TR>
<TH>Идентификатор</TH><TH>Полное имя</TH><TH>Деньги</TH>
<TH>Дата регистрации</TH><TH>Адрес E-Mail</TH><TH>Команды</TH>
</TR>
<%
  var nSumm=0;
  var nCounter=0;
  if(rs.EOF)
  {
%>
<TR><TD COLSPAN=6 ALIGN="CENTER">[Список покупателей пуст]</TD></TR>
<%
}
else
{
  i=0;
  while (!rs.EOF)
  {
     nSumm += (rs.Fields("Money").value)*100;
     nCounter++;
     var sID=rs.Fields("ClientID").value;
%>
<TR ID="A<%=sID%>">
<TD><b><%=rs.Fields("UserID").value%></TD>
<TD><%=rs.Fields("UserName").value%></TD>
<TD><%=rs.Fields("Money").value%></TD>
<TD><%=rs.Fields("RegisterDate").value%></TD>
<TD><%=rs.Fields("Email").value%></TD>
<TD>
<a href="EditUser.asp?ID=<%=sID%>" target="main">Изменить</A>&nbsp;
<a href="order.asp?ID=<%=rs.Fields("UserID").value%>" target="main">Корзина</A>
<a href="javascript:trydeluser(<%=sID%>, '<%=rs.Fields("UserName").value%>')" target="main">Удалить</A>
</TD>
</TR>
<%
     rs.MoveNext();
  }
}
rs.Close();
connect.Close();
%>

<TR>
<TD COLSPAN="2"><b>Всего покупателей: <%=nCounter%></b></TD><TD><%=nSumm/100%></TD><TD COLSPAN="3">&nbsp;</TD>
</TR>
</TABLE>

Для обеспечения возможности работы с дробными значениями денежных сумм мы вначале умножаем на 100 деньги, полученные от каждого покупателя, а затем делим на  100 общую сумму.

В каждой строке создаваемой таблицы серверный сценарий располагает ссылки для изменения или удаления учетной записи, а также для просмотра содержимого корзины покупателя. Операции редактирования учетной записи и просмотра корзины выполняются при помощи страниц EditUser.asp и order.asp. Что же касается удаления, то для этого мы вызываем функцию клиентского сценария с именем trydeluser. В качестве параметров данной функции передаются идентификатор пользователя и его имя.

Рассмотрим исходный текст хранимой процедуры SearchUsers (листинг 14-47).

Листинг 14-47. Вы найдете в файле chap14\BookShopScripts\dbo.SearchUsers.PRC на прилагаемом к книге компакт-диске

Она выполняет поиск учетных записей покупателей в таблице clients в соответствии с параметрами поиска.

Параметр поиска @DateCheck задает необходимость отбора учетных записей покупателей по дате их регистрации в базе данных магазина. Если этот параметр указан как «no» (это будет в том случае, если в форме поиска мы сняли отметку с переключателя искать по дате регистрации:), дата регистрации не проверяется. Если же это не так, то для удовлетворения условиям поиска дата регистрации должна находится в пределах, заданных параметрами @from и @to:

CREATE PROCEDURE SearchUsers @from datetime =null,
@to datetime =null, @Login varchar(20), @Email varchar(80), @DateCheck varchar(20) AS

IF @from IS NULL
BEGIN
  SELECT @to=GETDATE()
  SELECT @from=DATEADD(dd, -7, @to)
END

Для отбора данных по имени пользователя и его адресу электронной почты мы применили оператор LIKE, допускающий использование символов шаблона:

SELECT ClientID, USerID, Password, Language, clients.Money, Status, LastLogin, LoginCount, UserName, Email, mail, spam, RegisterDate, RegisterIP
FROM clients
WHERE
  (@DateCheck='no' OR (RegisterDate>=@from AND RegisterDate<=@to))
AND
  UserID LIKE @Login
AND
  Email LIKE @Email

Удаление записи покупателя

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

Рассмотрим работу функции trydeluser (листинг 14-46). Ее основная задача заключается в отображении предупреждающего сообщения об удалении пользователя, а также в предотвращении удаления учетных записей пользователей, отобравших в свои корзины какие-либо книги (то есть активных покупателей).

Для отображения предупреждающего сообщения об удалении учетной записи посетителя эта функция отображает на экране модельную диалоговую панель trydeleteuserdlg.asp (листинг 14-48), вызывая ее при помощи функции клиентского сценария showModalDialog. При этом функция trydeluser передает странице trydeleteuserdlg.asp массив параметров vParm с идентификатором пользователя и его именем, используемым для входа в магазин.

Листинг 14-48. Вы найдете в файле chap14\ BookShop\trydeleteuserdlg.asp на прилагаемом к книге компакт-диске

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

<h3>Внимание!</h3>
<p>Учетная запись<br><b><script LANGUAGE="javascript">
<!--
document.write(window.dialogArguments[1]);
//-->
</script></b><br>будет удалена!

Если пользователь решит продолжить удаление и щелкнет ссылку Удалить, управление получит функция клиентского сценария tryDeleteAcc, определенная на странице trydeleteuserdlg.asp. При отказе от удаления с помощью ссылки Отменить будет вызвана функция клиентского сценария cancelDeleteAcc:

<a onclick="tryDeleteAcc()">
  <font color="red">Удалить</font></a>
. . .
<a onclick="cancelDeleteAcc()">
  <font color="red">Отменить</font></a>

Функция tryDeleteAcc завершает работу модельной диалоговой панели, возвращая значение true:

function tryDeleteAcc()
{
  window.returnValue=true;
  event.returnValue=false;
  window.close();
}

Функция cancelDeleteAcc сообщает об отмене удаления возвращением значения false:

function cancelDeleteAcc()
{
  window.returnValue=false;
  event.returnValue=false;
  window.close();
}

Теперь мы снова должны вернуться к функции trydeluser.

Если сотрудник магазина решил продолжить удаление учетной записи, эта функция создает еще одну модальную диалоговую панель, загружая в нее страницу trydeleteacc.asp:

var sASP="";
sASP="trydeleteacc.asp?ID=" + sUserID;
rVal=showModalDialog(sASP, vParm,
 "dialogHeight:160px;dialogWidth:350px;status:0");
if(rVal==false)
  return;

Страница trydeleteacc.asp пытается удалить учетную запись посетителя из базы данных. Если это ей удается, мы удаляем средствами DHTML строку с этой записью из общего списка:

sNode="A"+sUserID;
var oDeletedRow=document.getElementById(sNode);
oDeletedRow.removeNode(true);

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

Рассмотрим исходный текст страницы trydeleteacc.asp со сценарием, выполняющим попытку удаления учетной записи из базы данных (листинг 14-49).

Листинг 14-49. Вы найдете в файле chap14\BookShop\trydeleteacc.asp на прилагаемом к книге компакт-диске

Получив управление, сценарий проверяет текущие права сотрудника, разрешая удалять учетные записи посетителей только администраторам. Далее вызывается хранимая процедура DeleteUser, выполняющая попытку удаления. Ей передается один входной параметр ID (идентификатор пользователя) и один выходной DelOK, сообщающий о результате выполнения операции удаления (для примера мы в этом и некоторых других сценариях передаем методу Append числовые, а не символьные значения):

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
var DelOk;
cmd.CommandText = "DeleteUser";
cmd.CommandType = 4;
cmd.ActiveConnection = connect;
 
cmd.Parameters.Append(cmd.CreateParameter(
  "User", 3, 1, 4, Request("ID")(1)));
    
cmd.Parameters.Append(DelOk=cmd.CreateParameter(
  "DelOk", 3, 3, 4, 0));
    
cmd.Execute();

После выполнения хранимой процедуры DeleteUser серверный сценарий анализирует содержимое выходного параметра DelOK и формирует соответствующее сообщение. Кроме того, в зависимости от результата операции создается один из двух вариантов функции клиентского сценария closeDialogOK, закрывающей окно модальной диалоговой панели. Если удаление прошло успешно, эта  функция возвращает значение true, а если нет false:

DelOk = DelOk.Value;
if(DelOk == 0)
{
%>
<script LANGUAGE="javascript">
<!--
function closeDialogOK()
{
  window.returnValue=true;
  event.returnValue=false;
  window.close();
}
//-->
</script>
<table width="100%" height="100%">
  <tr height="50%">
     <td width="100%" align="middle" valign="bottom" colspan="2">
     <p>Учетная запись <br><b><script LANGUAGE="javascript">
<!--
document.write(window.dialogArguments[1]);
//-->
</script></b><br>успешно удалена</td>
  </tr>
  <tr height="50%">
     <td width="45%" align="middle" valign="top">
     <a onclick="closeDialogOK()">
     <font color="red">OK</font></a></td>
  </tr>
</table>
<%
}
else
{
%>
<script LANGUAGE="javascript">
<!--
function closeDialogOK()
{
  window.returnValue=false;
  event.returnValue=false;
  window.close();
}
//-->
</script>
<table width="100%" height="100%">
  <tr height="50%">
     <td width="100%" align="middle" valign="bottom" colspan="2">
     <p>Невозможно удалить активную учетную запись:<p><b><script LANGUAGE="javascript">
document.write(window.dialogArguments[1]);
//-->
</script></b></td>
  </tr>
  <tr height="50%">
     <td width="45%" align="middle" valign="top">
     <a onclick="closeDialogOK()">
     <font color="red">OK</font></a></td>
  </tr>
</table>
<%
}

Исходный текст хранимой процедуры DeleteUser мы привели в листинге 14-50.

Листинг 14-50. Вы найдете в файле chap14\BookShopScripts\dbo.DeleteUser.PRC на прилагаемом к книге компакт-диске

В этой процедуре мы создаем локальную переменную @Status, присваивая ей нулевое значение. Если данный посетитель имеет записи в таблице orders (то есть если он отобрал книги для покупки), мы считаем его активным и устанавливаем содержимое переменной @Status, равное единице:

CREATE PROCEDURE DeleteUser @ID int, @Ok int =0 output AS

DECLARE @Status int
SELECT @Status=0

IF EXISTS(SELECT * FROM orders WHERE ClientID=@ID)
  SELECT @Status=1

Для пассивных посетителей выполняется удаление регистрационных записей из таблицы clients:

IF @Status=0 BEGIN
  DELETE clients WHERE ClientID=@ID
END

Результат выполнения операции удаления в любом случае записывается в выходной параметр @Ok:

SELECT @Ok=@Status

Просмотр содержимого корзины покупателя

Сотрудник магазина может просмотреть содержимое корзин покупателей при помощи страницы order.asp (листинг 14-51). Эта страница почти такая же, что и страница просмотра корзины в приложении покупателя, однако, в ней не предусмотрено изменение содержимого корзины.

Листинг 14-51. Вы найдете в файле chap14\BookShop\order.asp на прилагаемом к книге компакт-диске

Серверный сценарий, расположенный на этой странице, вызывает хранимую процедуру ListOrders, которая уже была описана ранее в разделах, посвященных приложению покупателя:

var ClientID=Request("ID")(1);

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout = 10;
connect.Open("DSN=BookStore", "dbo", "");
 
cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "ListOrders";
cmd.CommandType = adCmdStoredProc;
cmd.ActiveConnection = connect;
 
cmd.Parameters.Append(cmd.CreateParameter(
  "ClientID", adVarChar, adParamInput, 50, ClientID));

var rs;
rs=cmd.Execute();

Идентификатор покупателя (корзину которого мы будем смотреть) извлекается сценарием из параметра ID и затем передается хранимой процедуре с использованием локальной переменной ClientID.

Далее сценарий формирует таблицу, содержащую список книг, отобранных покупателем:

<h2>Содержимое корзины покупателя <%=ClientID%></h2>
<TABLE BORDER=1>
<%
while (!rs.EOF)
{
%>
<tr><td><b><%=rs.Fields("Author")%>. <%=rs.Fields("Title")%></b>
<br><i><%=rs.Fields("Publisher")%></i></td>
<td><%=rs.Fields("Price")%> у.е.</td><tr>
<%
  rs.MoveNext();
}
rs.Close();
connect.Close();
%>
</TABLE>

Редактирование регистрационных данных покупателя

Эта операция выполняется в два приема. Вначале загружается страница EditUser.asp, исходный текст которой представлен в листинге 14-52. Она получает сведения о регистрационной записи покупателя из базы данных магазина и отображает их в форме. Затем данные из формы попадают на страницу UpdateUser.asp, обновляющую запись в базе данных.

Листинг 14-52. Вы найдете в файле chap14\BookShop\EditUser.asp на прилагаемом к книге компакт-диске

В начале своей работы страница EditUser.asp проверяет права текущего пользователя, разрешая редактирование регистрационных записей покупателей только администраторам. Затем выполняется запуск хранимой процедуры GetUser, извлекающей регистрационную запись из базы данных. В качестве входного параметра мы передаем этой процедуре идентификатор покупателя:

connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "GetUser";
cmd.CommandType = 4;
cmd.ActiveConnection = connect;

var ID = cmd.CreateParameter(
  "ID", adInteger, adParamInput, 4, Request("ID")(1));
cmd.Parameters.Append(ID);

var UserID = cmd.CreateParameter(
  "UserID", adVarChar, adParamOutput, 50, " ");
cmd.Parameters.Append(UserID);

var Pass = cmd.CreateParameter(
  "Pass", adVarChar, adParamOutput, 50, " ");
cmd.Parameters.Append(Pass);

var Language = cmd.CreateParameter(
  "Language", adVarChar, adParamOutput, 50, " ");
cmd.Parameters.Append(Language);

var Money= cmd.CreateParameter(
  "Money", adCurrency, adParamOutput, 8, "0");
cmd.Parameters.Append(Money);

var RegisterDate = cmd.CreateParameter(
  "RegisterDate", adDBTimeStamp, adParamOutput, 8, 0);
cmd.Parameters.Append(RegisterDate);

var RegisterIP = cmd.CreateParameter(
  "RegisterIP", adVarChar, adParamOutput, 15, " ");
cmd.Parameters.Append(RegisterIP);

var Email = cmd.CreateParameter(
  "Email", adVarChar, adParamOutput, 80, " ");
cmd.Parameters.Append(Email);

cmd.Execute();

Обратите внимание, как мы инициализируем параметры хранимой процедуры, имеющие отношение к данным различных типов.

Для целых чисел мы указываем константу adInteger, текстовые строки передаются с использованием константы adVarChar, а для передачи денежных данных применяется константа adCurrency. И, наконец, отметка о времени передается с использованием константы adDBTimeStamp.

Значения, полученные от хранимой процедуры, используются для инициализации полей формы, предназначенной для редактирования учетной записи посетителя:

<FORM ACTION="UpdateUser.asp" METHOD="post">
<H2>Редактирование учетной записи посетителя "<%=UserID.Value%>"</H2>
<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=0>
<TR><TD>Идентификатор</TD><TD>
<INPUT SIZE=20 TYPE="hidden" NAME="ID" VALUE="<%=ID.Value%>">
<INPUT SIZE=20 TYPE="EDIT" NAME="USR" VALUE="<%=UserID.Value%>">
</TD></TR>
<TR><TD>Пароль</TD><TD>
<INPUT TYPE="EDIT" NAME="PWD" VALUE="<%=Pass.Value%>">
</TD></TR><TR><TD>Язык</TD><TD>"<%=Language.Value%>"</TD></TR>
<TR><TD>Деньги</TD><TD>"<%=Money.Value%>"</TD></TR>
<TR><TD>Дата регистрации</TD><TD>
<%
var sRegDate="";
sRegDate=RegisterDate.Value;
if(sRegDate==null)
{ sRegDate="не известна" }
%>
<%=sRegDate%>
</TD></TR><TR><TD>Адрес IP при регистрации</TD><TD>
<%
sIP=RegisterIP.Value;
if(sIP==null)
{sIP="не известен"}
%>
<%=sIP%></TD></TR>
<TR><TD>Адрес Email</TD><TD>
<%
var sEmail="";
sEmail=Email.Value;
if(sEmail==null)
{sEmail="не известен"}
%>
<INPUT TYPE="EDIT" NAME="EMAIL" VALUE="<%=sEmail%>">
</TD></TR><TR><TD>&nbsp;</TD><TD>
<INPUT TYPE="submit" VALUE="Обновить">
</TD></TR></TABLE></FORM></TD></TR></TABLE>

После того как администратор магазина отредактирует учетную запись покупателя, он должен щелкнуть кнопку Обновить. В результате будет загружена страница UpdateUser.asp, которой будут переданы обновленные данные из полей форм, а также идентификатор учетной записи пользователя в скрытом поле формы.

Исходный текст хранимой процедуры GetUser представлен в листинге 14-53.

Листинг 14-53. Вы найдете в файле chap14\BookShopScripts\dbo.GetUser.PRC на прилагаемом к книге компакт-диске

Эта процедура просто выбирает поля учетной записи пользователя, возвращая их через выходные параметры.

CREATE PROCEDURE GetUser @ID int, @UserID varchar(50) output, @Pass varchar(50) output, @Language varchar(50) output, @Money money output,   @RegisterDate datetime output, @RegisterIP varchar(15) output, @Email varchar(80) output AS

SELECT @UserID="", @Pass="", @Language="", @Money=0, @RegisterDate="", @RegisterIP="", @Email=""

SELECT @UserID=UserID, @Pass=Password, @Language=Language, @Money=Money, @RegisterDate=RegisterDate, @RegisterIP=RegisterIP, @Email=Email
FROM clients WHERE ClientID=@ID

Исходный текст страницы UpdateUser.asp, выполняющей обновление регистрационной записи пользователя, показан в листинге 14-54.

Листинг 14-54. Вы найдете в файле chap14\BookShop\UpdateUser.asp на прилагаемом к книге компакт-диске

<%@ LANGUAGE = "JScript" %>
<!-- #include file="header.asp" -->
<%
 
  Response.Redirect("GetSearchResults.asp?MODE=restart");
}
%>
<!-- #include file="footer.asp" -->

В начале своей работы серверный сценарий, расположенный на этой странице, проверяет права пользователя. Мы разрешаем изменять учетные записи покупателей только администраторам.

Далее сценарий вызывает хранимую процедуру SetUserData, передавая ей через входные параметры идентификатор пользователя и обновленное содержимое полей учетной записи:

var rs, connect;
connect = Server.CreateObject("ADODB.Connection");
connect.ConnectionTimeout = 15;
connect.CommandTimeout =  10;
connect.Open("DSN=BookStore", "dbo", "");

var cmd = Server.CreateObject("ADODB.Command");
cmd.CommandText = "SetUserData";
cmd.CommandType = 4;
cmd.ActiveConnection = connect;

var ID=cmd.CreateParameter(
  "ID", 3, 1, 4, Request("ID")(1));
    
var Login=cmd.CreateParameter(
  "Name", 200, 1, 20,  Request("USR")(1));
    
var Pass=cmd.CreateParameter(
  "Pass", 200, 1, 20, Request("PWD")(1));
    
var Email=cmd.CreateParameter(
  "Email", 200, 1, 80, Request("EMAIL")(1));

cmd.Parameters.Append(ID);
cmd.Parameters.Append(Login);
cmd.Parameters.Append(Pass);
cmd.Parameters.Append(Email);
cmd.Execute();
connect.Close();

После обновления записи мы вновь попадаем на страницу GetSearchResults.asp, которая теперь вызывается с параметром MODE, имеющим значение «restart»:

Response.Redirect("GetSearchResults.asp?MODE=restart");

Исходный текст хранимой процедуры SetUserData представлен в листинге 14-55.

Листинг 14-55. Вы найдете в файле chap14\BookShopScripts\dbo.SetUserData.PRC на прилагаемом к книге компакт-диске

Она обновляет поля таблицы clients значениями, полученными через свои параметры:

CREATE PROCEDURE SetUserData @ID int, @Name varchar(50),
  @Pass varchar(50), @Email varchar(80) AS
UPDATE clients SET UserID=@Name, Password=@Pass, Email=@Email
WHERE ClientID=@ID

[Назад] [Содержание] [Дальше]