Основы ASP.
Dynamic HTML представляет собой основное средство программирования клиента для Microsoft Internet Explorer 4.0 и выше, но такие программы просмотра Web, как Netscape Navigator, не поддерживают Dynamic HTML. На самом деле очень малая часть функциональности клиентской части, поддерживаемой различными программами просмотра, может рассматриваться как действительно кросс-платформенная.
Если Вы хотите разработать Интернет-узел, открытый для доступа самым различным программам просмотра, то должны перенести программирование с клиента на сервер. Такую возможность предоставляют Microsoft ASP (Active Server Pages — активные серверные страницы). По сути ASP не что иное, как сценарий на VBScript, который исполняется на сервере. Когда запрашивается страница, этот сценарий порождает HTML-текст. Это ключевая особенность ASP — клиент никогда не видит вашего кода, а только результирующий HTML, который воспринимает любая программа просмотра.
Листинг 4.1 демонстрирует простую ASP-страницу, которая создает приветствие в соответствии со временем суток. В нем текущий час определяется при помощи кода Hour(Now), где Now — функция VBScript, возвращающая текущий момент времени и дату. Если текущий час меньше 12, то приветствие задается в форме «Доброе утро!» От полудня до шести вечера сообщение имеет вид «Добрый день!», а после шести — «Добрый вечер!»
Листинг 4.1.Простой пример ASP.
<%@ LANGUAGE="VBSCRIPT" %>
<HTML> <head>
<MEТА HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=windows-1251">
<TITLE>Simple ASP Example</TITLE> </HEAD><BODY BGCOLOR="#FFFFFF">
<%
Dim strGreeting
If Hour(Now) < 12 Then
strGreeting = "Доброе утро!"
ElseIf Hour(Now) > 11 And Hour(Now) < 18 Then
StrGreeting = "Добрый день"
ElseIf Hour(Now) > 17 Then
strGreeting = "Добрый вечер!"
End If
%>
<CENTER><H1><%=strGreeting%> </Н1>
</BODY></HTML>
Обратите внимание на код в листинге, окруженный специальными символами: угловыми скобками и знаками процента (<%...%>). Такие символы означают, что это серверный код, который выполняется перед тем, как страница будет на самом деле послана программе просмотра. Если бы Вы посмотрели в Internet Explorer на результирующий HTML-текст, то увидели бы следующее (в предположении, что сейчас еще не вечер, но уже не утро):
<%@ LANGUAGE="VBSCRIPT" %>
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=windows-1251">
<TITLE>Simple ASP Example</TITLE> </HEAD>
<BODY BGCOLOR="#FFFFFF"> <Н1>Добрый день!</Н1> </BODY> </HTML>
В этом-то и состоит суть ASP. Результат исполнения кода — обыкновенный HTML! Эту страницу можно просматривать любой программой просмотра: не только Internet Explorer, но и, например, Netscape Navigator. Иными словами, ASP предоставляет разработчику подлинную платформенную независимость
У представленного кода есть еще несколько особенностей. Обратите внимание на самую верхнюю строчку — она определяет, на каком языке написан сценарий на данной странице:
<%@ LANGUAGE="VBSCRIPT" %>
Скорее всего, Вы будете писать свои сценарии на VBScript, но ASP поддерживает и JavaScript. В отличие от сценариев на клиентской стороне, здесь выбор языка абсолютно не создает проблем совместимости с различными программами просмотра, поскольку весь код исполняется на сервере.
А теперь обратите внимание на ту строку, где и происходит генерация HTML-текста. Здесь для вывода приветствия используется переменная:
<H1><%=strGreeting%> </H1>
Переменная strGreeting заключена в угловые скобки со знаками процента, как и весь остальной серверный код, но, кроме того, ей предшествует знак равенства. Такая конструкция играет важную роль в ASP, указывая, что в данное место HTML-страницы нужно вставить текущее значение этой переменной.
Объекты и компоненты.На самом простом уровне создание ASP-страницы — это ни что иное, как написание серверного кода для получения ожидаемого результата. Но VBScript не является полнофункциональным языком и, как только Вы приступаете к построению более сложных страниц, его выразительных средств начинает не хватать. Так, в VBScript нет встроенных функций доступа к данным; не умеет он и открывать текстовые файлы. Собственно говоря, в VBScript отсутствуют какие-либо встроенные средства доступа к каким бы то ни было внешним источникам данных. Так как же в таком случае при помощи ASP выполняются такие сложные действия, как доступ к данным? Ответ будет таким: нужно дополнить VBScript объектами и компонентами ASP.
ASP-объекты и компоненты — это не что иное, как компоненты ActiveX, подобные обычным DLL ActiveX, с которыми Вы наверняка работали в Microsoft Visual Basic. Различие между объектами и компонентами ASP состоит в том, каким образом они появляются в программе. ASP-объекты — это элементы управления ActiveX, которые в коде на VBScript доступны всегда: их не нужно создавать явно. В число объектов ASP входят Application, Session, Request, Response и Server. А вот ASP-компоненты представляют собой DLL, существующие вне структуры ASP. Эти компоненты могут быть написаны на любом языке, а некоторые полезные ASP-компоненты просто поставляются в комплекте с Visual InterDev. ASP-компоненты нужно явно создавать в коде. ASP поддерживает компоненты Database Access, File Access, Browser Capabilities, Ad Rotator и Content Linking.
Файл GLOBAL.ASA.Одна из главных трудностей разработчика для Интернета, независимо от того, какую технологию он использует, состоит в том, как сложно создать в Интернете настоящее приложение. Взаимодействие программы просмотра и Web-сервера представляет собой по сути лишенную состояния транзакцию, в ходе которой сервер посылает клиенту Web-страницу и затем забывает о его существовании. Когда клиент запрашивает другую Web-страницу, сервер ничего не помнит о предыдущем запросе. Коренная проблема для всех Web-приложений такова: как показать, что это именно приложение?
Определить приложение в среде Microsoft Windows довольно просто. Приложение запускается двойным щелчком значка и завершается, когда в меню File выбран пункт Exit. В промежутке между двумя этими событиями данные хранятся в переменных. Но для Интернет-приложений это не так. Как определить, когда приложение начинается, а когда заканчивается? Можно сказать, что приложение начало работу, если пользователь зашел на узел и просматривает одну из его страниц. Но что если он переходит к другому узлу, а через пять минут возвращается? Приложение все еще активно? А если пользователь отсутствовал час или два?
Проблема определения моментов запуска и завершения приложения оказывает серьезное влияние на правильное управление переменными и последовательностью выполнения. К счастью, ASP предлагает решение. Оно состоит в том, что для определения начала и завершения — как всего приложения, так и отдельных пользовательских сессий — используется специальный файл под названием GLOBAL.ASA. На этот файл возложено реагирование на четыре ключевых события узла: Application_OnStart (запуск приложения), Application_OnEnd (завершение приложения), Session_OnStart (начало сессии) и Session_OnEnd (завершение сессии). В листинге 4.2 приведен типичный файл GLOBAL.ASA.
Листинг 4.2.Файл GLOBAL.ASA.
<SCRIPT LANGUAGE="VBSCRIPT" RUNAT="Server">
' В этот файл можно добавить обработчики событий ASP.
' Для создания обработчиков внесите в файл подпрограмму с именем,
' соответствующим событию, на которое Вы бы хотели среагировать.
'Название события Описание
'SessionOnStart Происходит, когда пользователь в первый раз вы-
' полняет любую страницу Вашего приложения
SessionOnEnd Происходит, когда превышен лимит времени,
' в течение которого пользователь не обращается
' к страницам Вашего приложения, или если имел
' место явный выход
'Application_OnStart Происходит один раз, когда любой
' пользователь впервые выполняет первую страницу
' Вашего приложения
'Application_OnEnd Происходит один раз при остановке Web-сервера
Sub SessionOnStart
End Sub
Sub Session_OnEnd
End Sub
Sub ApplicationOnStart
End Sub
Sub Application On_End
End Sub
</SCRIPT>
Для обозначения разделов сценария GLOBAL.ASA содержит теги <SCRIPT>. Эти теги имеют особый атрибут RUNAT=Server, который означает, что содержащийся в теге код на VBScript должен исполняться на сервере, а не на клиенте. Функционально RUNAT=Server означает то же, что и сочетания угловых скобок и знака процента, используемые для обозначения серверного сценария на Web-страницах. Обработка стандартных событий на сервере записывается в GLOBAL.ASA в стандартном синтаксисе. Например, обработку запуска приложения выполняет следующий фрагмент кода:
<SCRIPT LANGUAGE=VBScript RUNAT=Server>
Sub Application_OnStart
' Конкретный код приложения
End Sub </SCRIPT>
Хотя GLOBAL.ASA отмечает начало и завершение приложения при помощи событий, остается неясным, что же все-таки составляет собственно приложение. Одна из рабочих формулировок, предложенная Microsoft, определяет Интернет-приложение как виртуальный каталог со всеми его файлами. Если пользователь запрашивает Web-страницу из виртуального каталога под названием Bookstore, то тем самым он запускает приложение Bookstore, и в GLOBAL.ASA возбуждаются события Application_OnStart и Session_OnStart.
Согласно этому определению с приложением одновременно могут работать несколько программ просмотра. Но событие Application_OnStart происходит только один раз: когда первый пользователь запрашивает Web-страницу из виртуального каталога. Когда затем страницы из этого каталога запрашивают другие пользователи, возбуждается только событие Session_OnStart.
В то время как приложение может относиться к нескольким программам просмотра, обращающимся к одному и тому же множеству Web-страниц, сессия касается какой-то одной программы просмотра, обращающейся к тем же Web-страницам. Для конкретной программы просмотра сессия длится, пока программа продолжает запрашивать страницы виртуального каталога. Если же пользователь не запрашивает Web-страницы (из данного виртуального каталога) на протяжении 20 минут (по умолчанию), сессия завершается, и возбуждается событие Session_OnEnd. Когда в данном виртуальном каталоге завершаются все сессии, возбуждается событие Application_OnEnd.
В качестве примера рассмотрим следующий сценарий. Два пользователя намереваются посетить на Web-узле приложение Magazine. Пользователь 1 оказывается проворнее и быстренько запрашивает Web-страницу DEFAULT.ASP. Тут же возбуждаются события Application_OnStart и Session_OnStart. Буквально пятью минутами позже к приложению обращается пользователь 2. Поскольку пользователь 1 как-то проявлял себя в течение последних 20 минут, приложение Magazine активно. Следовательно, возбуждается только событие Session_OnStart, сигнализируя о начале новой сессии. Кроме того, теперь для завершения приложения необходимо, чтобы завершились обе сессии.
В течение следующих 15 минут пользователь 1 не запрашивает никаких страниц приложения Magazine. Поскольку он не проявлял активности на протяжении 20 минут, ASP приходит к выводу, что пользователь 1 закончил свою работу с приложением, и возбуждает событие Session_OnEnd. Но приложение все еще активно, поскольку в течение последних 20 минут к нему обращался пользователь 2.
Пользователь 2 работает с приложением еще час, то и дело запрашивая новые Web-страницы. Но в конце концов он отключается, а через 20 минут после того, как он покинул узел (точнее, в последний раз запросил Web-страницу приложения), возбуждается событие Session_OnEnd. Поскольку пользователь 2 был последним пользователем данного приложения, оно завершается, и возбуждается событие Application_OnEnd.
Объекты.
В ASP есть несколько встроенных объектов, которые доступны разработчику. Эти объекты помогают управлять многими вещами: от переменных, до передачи форм. Работать с ними легко, они вызываются из кода напрямую без какого-то особого синтаксиса.
Объект Application.Объект Application (приложение) позволяет создавать переменные приложения (application variables) - переменные, доступные всем пользователям данного приложения. Все, кто обращается к Web-страницам данного виртуального каталога, могут совместно использовать любую переменную приложения определенную для этого каталога.
В листинге 4.3 приведен пример программы, которая использует Объект Application. В нем переменная приложения служит для отслеживания времени последнего обращения к страницам приложения.
Листинг 4.3.Объект Application.
<%@ LANGUAGE ="VBScript"%>
<html><head><title>Application Variables</TITLE>
</HEAD><BODY><CENTER>
Эта страница последний раз посещалась: <%=Application("Time")%>
<% Application.Lock
Application("Time")=Now
Application.UnLock %>
</BODY></HTML>
Создание переменной приложения сводится к адресации объекта Application именем новой переменной, которую вы хотите создать. Например, следующий код создает новую переменную приложения с именем Company и присваивает ей значение NewTech.
Application("Company")="NewTech"
Имя может быть произвольным, а переменная может содержать любую информацию, будь то число или текст.
Поскольку такие переменные доступны нескольким пользователям одновременно, вы не сможете гарантировать, что два пользователя не попытаются одновременно присвоить одной и той же переменной разные значения. Для разрешения подобных коллизий объект Application поддерживает методы Lock и UnLock. Метод Lock блокирует весь объект Application, а не только переменную, вы хотите изменить, поэтому сразу же после изменения значения переменной разблокируйте объект:
Application.Lock
Application("Company")="NewTech"
Application.UnLock
Несмотря на то, что переменные приложения пригодны для временного хранения данных, их нельзя использовать для долговременного хранения. Все данные в переменных приложения уничтожаются, когда происходит событие Application_OnEnd. Так что, если вы хотите, чтобы они сохранились после завершения приложения, позаботьтесь о их переносе в файл или базу данных.
Объект Session.Зачастую разработчиков меньше интересуют данные, совместно используемые несколькими пользователями, зато гораздо больше - данные, связанные с конкретным пользователем. ASP поддерживает переменные для индивидуального пользователя при помощи объекта Session (сессия), который позволяет создавать переменные сессии (session variables).
Листинг 4.4 демонстрирует, как определить несколько переменных сессии в файле GLOBAL.ASA. Само по себе их определение так же просто, как и в случае переменных приложения. Все, что нужно сделать - это адресовать объект Session именем переменной, которую вы хотите создать. Основное различие между переменными этих объектов - их области видимости. Переменные сессии предназначаются для одного пользователя и живут, пока пользователь поддерживает сессию. Как только в течение 20 минут (по умолчанию) пользователь не обращается к страницам данного виртуального каталога, данные пропадают.
Листинг 4-..Создание переменных сессии.
<SCRIPT LANGUAGE="VBSCRIPT" RUNAT="Server">
Sub Session_OnStart
Session("Company")="NewTech"
Session("Email")="info@newtech.com"
End Sub
</SCRIPT>
Переменные сессии можно создавать на любой Web-странице или в файле GLOBAL.ASA, а доступны они на любой Web-странице приложения, в котором эти переменные были первоначально созданы. Получить значения переменных сессии можно, считывая их из объекта Session. Следующий фрагмент кода считывает переменные сессии, созданные в листинге 4.4, и выводит их в полях ввода:
<FORM>
<P><INPUT TYPE="TEXT" VALUE=<%=Session("Company")%>Компания</P>
<P><INPUT TYPE="TEXT" VALUE=<%=Session("Email")%>Эл. Почта</P>
</FORM>
Ранее мы определили Интернет-приложение как лишенные статуса транзакции между Web-сервером и программой просмотра. Как же тогда ASP запоминает переменные сессии для каждого пользователя приложения? Ответ будет таким: эти переменные сохраняются на сервере для каждого клиента. Программа просмотра получает от сервера уникальный идентификатор, позволяющий определить, какой набор переменных кому принадлежит. Клиент этот идентификатор (Globally Unique Identifier, GUID) сохраняет, а впоследствии посылает серверу и получает именно ему предназначенные данные. Таким образом каждый клиент может иметь свой набор данных в каждом Интернет-приложении.
Осталось сказать, что для установки или считывания впемени жизни сессии (в минутах) применяется свойство Timeout объекта Session:
Session.Timeout=30
Объект Request.Для передачи данные клиенту создается Web-страница, а для передачи данных в обратном направлении программа просмотра использует отправку формы (form submission). В форме содержатся текстовые поля, переключатели и т.п. Клиент размещает введенные данные в этих полях и пересылает пакет серверу. Процессом передачи формы управляют два атрибута тега <FORM>: METHOD и ACTION. Первый атрибут - METHOD - определяет, каким именно образом данные пересылаются серверу. Атрибут может иметь два значения: POST и GET. POST диктует программе просмотра, что данные нужно поместить внутрь формы, а GET пересылает данные как составную часть URL целевой страницы. Второй атрибут - ACTION - задает целевую страницу для обработки отправленных данных. Следующий код посылает все данные формы сценарию DATA.ASP методом POST:
<FORM METHOD="POST" ACTION="/l5/data.asp">
<P><INPUT TYPE="TEXT" NAME="Name"></P>
<P><INPUT TYPE="TEXT" NAME="EMail"></P>
<P><INPUT TYPE="SUBMIT"></P>
</FORM>
Элемент формы с типом SUBMIT - это кнопка, нажатие которой пользователем заставляет программу просмотра упаковать данные формы и отправить их. Формат пересылки данных определен строго и сервер знает, чего ожидать от клиента. Данные имеют вид пар Поле=Значение, отсылаемых серверу в формате открытого текста. Если в предыдущем примере ввести в поле Name NewTech и info@newtech.com в поле Email, то сценарию DATA.ASP будет послан следующий текст:
Name=NewTech&Email=info@newtech.com
На сервере эти данные можно вновь разобрать по полям и использовать в любых целях. Вот тут-то и нужен объект Request. Он используется в ASP для разбора полученных от клиента данных. Для работы с объектом Request просто сообщите ему имя поля, значение которого хотите получить, и объект вернет вам это значение. Например, следующий код вернет вам значение поля Name:
<%=Request.Form("Name")%>
Request.Form применяется, когда данные были отправлены методом POST и именно этому сценарию. Если для отправки данных используется метод GET или сценарий вызывается с передачей параметров прямо в гиперссылке
<A HREF=/l5/data.asp?Name=NewTech&Email=info@newtech.com> Чтобы отправить данные, щелкните здесь!</A>
то для разбота данных применяют свойство Request.QueryString, который работает так же, как Request.Form. Следующий фрагмент кода вернет значение поля Name из гиперссылки:
<%=Request.QueryString("Name")%>
Другое свойство - Request.Cookies используются для извлечения информации из кукисов (cookies), отосланных вместе с запросом строке пользовательского агента программы просмотра. А листинг 4.5 демонстрирует применение свойства ServerVariables для определения имени компьютера, с которого клиент вызвал сценарий.
Листинг 4.5.Определение компьютера пользователя.
<%@ LANGUAGE="VBSCRIPT"%>
<html><head><title>Server Variables</TITLE>
</HEAD><BODY><CENTER>Вы вошли с компьютера
<%=Request.ServerVariables("Remote_Host")%>
</BODY></HTML>
Переменные сервера представляют широкий круг информации о клиенте и Web-сервере. Доступ к каждой конкретной переменной сводится к чтению соответствующей переменной.
Объект Response.Этот объект управляет содержимым страницы, которую ASP возвращает программе просмотра. Фактически в комбинации <%=переменная%> знак равенства представляет собой сокращенное обозначение метода Write объекта Response. Так что следующие две строки кода эквивалентны:
<%="NewTech"%>
<%Response.Write "NewTech"%>
Поскольку объект Response используется очень часто, такое сокращение оправдано.
Полезное свойство объекта Response - Expires. Оно задает время (в минутах) за которое страница устаревает. Если установить его в нуль, то страница будет устаревать в момент загрузки и Internet Explorer не будет ее кэшировать. Кэширование сильно влияет на разработку и может привести к тому, что приложение будет функционировать неправильно. IE кэширует страницы двумя способами: на диске и в памяти. Рассмотрим такой фрагмент кода, показывающий текущее время и дату:
<CENTER>Сейчас <%=Now%>
Когда IE запрашивают страницу с этим кодом, на сервере выполняется сценарий, и на странице появляется текущее время. Однако, если программа просмотра переходит к другой странице, а затем возвращается к этой, со временем, то время не изменится, поскольку IE не запрашивает ее повторно. В листинге 4.6 приведена исправленная версия примера, устаревающая уже в момент загрузки.
Листинг 4.6.Страница, устаревающая уже в момент загрузки.
<%@ LANGUAGE="VBSCRIPT"%>
<%Response.Expires=-1%>
<HTML><HEAD><TITLE>Forcing a Page to Expire</TITLE></HEAD><BODY>
<Н1>Сейчас <%Response.Write Now%>
</BODY> </HTML>
Еще один полезный метод объекта Response - Redirect, перенаправляющий программу просмотра на указанный URL:
<% Response.Redirect "enter.asp"%>
Объект Server.Объект Server (сервер) представляет собой в некотором роде свалку — в том смысле, что предоставляемые им функции никак не связаны между собой, за тем исключением, что все они полезны разработчику для Интернета. Пожалуй, самая важная из всех функций объекта Server — это метод CreateObject, который создает экземпляр компонента ActiveX. Причем это может быть как встроенный компонент, входящий в комплект поставки, так и тот, который написали Вы сами на любом языке. В любом случае использование компонента ActiveX на сервере требует вызова метода CreateObject.
Аргументом метода CreateObject служит ProgID (программный идентификатор) требуемого компонента ActiveX. ProgID — это содержательное имя компонента, такое как Excel.Sheet или Word.Basic. Следующая строчка показывает, как при помощи CreateObject создать экземпляр компонента с ProgID Excel.Sheet.
Set MyObject = Server.CreateObject("Excel.Sheet")
Другим полезным методом объекта Server является MapPath, возвращающий фактический путь, соответствующий заданному виртуальному каталогу.
Компоненты.
Компоненты ASP — это на самом деле просто компоненты ActiveX, наподобие тех, что Вы можете сами создать на Visual Basic или Visual C++. Но эти компоненты написаны Microsoft и поставляются вместе с Visual InterDev. Они предназначены для выполнения полезных для Web-узлов задач общего характера, включая доступ к данным. Создать их на своей странице Вы можете при помощи метода CreateObject объекта Server, а как только они созданы, смело обращайтесь к их свойствам и методам для выполнения нужных Вам задач.
Компонент ActiveX Data Objects.Самым полезным изо всех компонентов ASP следует признать компонент доступа к базам данных, называемый также ActiveX Data Objects, или сокращенно ADO. Он и содержащиеся в нем объекты применяются для чтения и записи данных в источники данных ODBC при публикации в Web информации из баз данных.
Объект Connection (подсоединение) создается методом CreateObject объекта Server, и ссылка на него помещается в переменную. Когда объект создан, его можно использовать для открытия подсоединения к любому источнику данных ODBC. Следующий фрагмент кода устанавливает подсоединение к источнику данных ODBC с названием Publications:
<%
' Объявляем переменную
Dim objConnection
' Создаем объект Connection
Set objConnection = Server.CreateObject("ADODB.Connection")
' Открываем подсоединение к источнику данных
objConnection.Open "Publications", "sa", "" %>
Здесь objConnection — переменная для объектной ссылки на экземпляр объекта Connection. Метод Open устанавливает подсоединение, принимая в качестве аргументов имя источника данных, идентификатор пользователя и пароль.
Когда подсоединение установлено, получать информацию из источника данных можно при помощи объекта Recordset (набор записей). Этот объект умеет выполнять оператор SELECT языка SQL и возвращать набор записей, удовлетворяющих этому запросу. Как и объект Connection, Recordset создается методом CreateObject. В следующем примере программа выполняет оператор SELECT над источником данных, представленным переменной objConnection:
<%
' Объявляем переменную
Dim objRecordset
' Создаем объект
Recordset Set objRecordset =
Server.CreateObject("ADODB.Recordset")
' Выполняем запрос SQL
objRecordset.Open "SELECT *", objConnection
%>
После того, как записи получены, для передвижения по ним можно обращаться к методам MoveFirst, MoveLast, MoveNext и MovePrevious. Затем метод Write объекта Response помещает данные на Web-страницу, которая и посылается программе просмотра. В листинге 4.7 приведен полный пример ASP-страницы, которая строит список пользователей, содержащихся в источнике данных Data.
Листинг 4.7.Построение списка при помощи ADO.
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html; charset=windows-1251">
<TITLE>Using ADO</TITLE></HEAD><BODY>
<%
'Объявляем переменные
Dim objConnection
Dim objRecordset
' cоздаем объекты
Set objConnection = Server.CreateObject("ADODB.Connection")
Set objRecordset = Server.CreateObject("ADODB.Recordset")
' Устанавливаем подсоединение и выполняем запрос
objConnection.Open "Data", "", ""
objRecordset.Open "SELECT Name FROM Users", objConnection
%>
<!-- Строим список SELECT по набору данных -->
<SELECT SIZE=8>
<% Do While Not ObjRecordset.EOF %>
<!-- Создаем очередной элемент списка -->
<OPTION><%=objRecordset("Name")%>
</OPTION>
<% objRecordset.MoveNext
Loop %>
</SELECT></BODY></HTML>
Одна из основных задач в управляемом данными Web-приложении — управление информацией в объекте Recordset. Очень часто простой запрос возвращает гораздо больше данных, чем имеет смысл показывать. Давайте, например, посмотрим, что происходит, когда Вы обращаетесь к какой-либо поисковой системе в Интернете. Поисковая машина, получив ключевое слово, возвращает ссылки на узлы, где это ключевое слово встречается. Но зачастую обнаруживаются тысячи узлов, содержащих данное ключевое слово. Совершенно очевидно, что показать все эти узлы на одной Web-странице совершенно невозможно.
Выход состоит в разбиении на страницы (paging). Этот механизм реализован во всех поисковых системах для передачи за один раз некоей порции результатов запроса, скажем, из 10 записей. Теперь пользователь может эффективно работать с полученной информацией. Поддерживает разбиение на страницы и ADO — посредством нескольких свойств объекта Recordset: PageSize, PageCount и AbsolutePage.
При получении набора данных можно указать, что записи следует разбить на страницы. Количество строк набора данных, составляющих страницу, задается значением свойства PageSize. Затем можно определить общее количество страниц в наборе данных посредством свойства PageCount. А доступ к заданной странице обеспечивает свойство AbsolutePage.
В листинге 4.8 приведен полный пример, в котором пользователь может просматривать 10 записей за раз. Переменная сессии CurrentPage отслеживает текущую страницу. Пользователь может перейти к предыдущей порции данных или к следующему набору из 10 записей, выбрав одну из двух гипертекстовых ссылок на странице.
Листинг 4.8.Разбиение набора данных на страницы средствами ADO.
<%@LANGUAGE="VBScript" %>
<%Response.Expires=-1 %>
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html; charset=windows-1251">
<TITLE>Paging Records</TITLE> </HEAD> <BODY>
<%
' На какой мы странице?
Select Case Request.QueryString("Direction")
Case "" Session("CurrentPage") = 1
Case "Next" Session("CurrentPage") = Session("CurrentPage") + 1
Case "Prev" Session("CurrentPage") = Session("CurrentPage") - 1
End Select
' Константы
Const adOpenKeyset = 1
' Объявляем переменные
Dim objConnection
Dim objRecordset
' Открываем базу данных
Set objConnection = Server.CreateObject("ADODB.Connection")
objConnection.Open "Data", "", ""
' Конструируем оператор SQL
Dim strSQL
strSQL ="SELECT Name, About FROM Users"
' Создаем набор данных
Set objRecordset = Server.CreateObject("ADODB.Recordset")
objRecordset.PageSize = 10
objRecordset.Open strSQL, objConnection, adOpenKeyset
objRecordset.AbsolutePage = CLng(Session("CurrentPage"))
' Выводим результаты
%>
<P>Page <%=Session("CurrentPage")%> of
<%=objRecordset.PageCount%></P>
<TABLE BORDER>
<TR><TH>Пользователь</TH><TH>Сведения</TH>
</TR><%
Dim i
For i = 1 To objRecordset.PageSize
if NOT objRecordset.EOF Then
%>
<TR><TD><%=objRecordset("Name")%></TD>
<TD><%=objRecordset("About")%></TD>
</TR> <%
objRecordset.MoveNext
end if
Next %>
</TABLE>
<!-- Ссылка на СЛЕДУЮЩУЮ страницу -->
<% If CLng(Session("CurrentPage")) < objRecordset. PageCount Then %>
<P><A HREF="e8.asp?Direction=Next">Следующая страница</A></P>
<%End If%>
<!-- Ссылка на ПРЕДЫДУЩУЮ страницу -->
<% If CLng(Session("CurrentPage")) > 1 Then %>
<P><A HREF="e8.asp?Direction=Prev">Предыдущая страница</A></P>
<%End If%>
<%
' Закрываем базу данных
objRecordset.Close
objConnection.Close
Set objRecordset = Nothing
Set ObjConnection = Nothing %>
</BODY></HTML>
В этом примере применяются определенные приемы, которые стоит обсудить подробнее. Обратите внимание, что весь процесс разбиения на страницы обеспечивается одним ASP-файлом. Для каждой страницы данных вновь вызывается тот же самый ASP-файл. Обычно при вызове страницы Internet Explorer получает ее из памяти клиентского компьютера. В нашем примере страница всегда будет находиться в памяти, поскольку вызывается постоянно. Налицо проблема: ведь запрос выполняется только тогда, когда выполняется код на сервере. Поэтому мы должны предотвратить использование ASP-файлов из памяти. Для этого следует установить свойство Expires объекта Response в нуль. Тогда файл будет обновляться при каждом новом обращении к странице, что нам и требуется.
Обратите также внимание, что при каждом обращении к странице выполняется один и тот же запрос, меняется только свойство Absolute-Page. Такая стратегия кажется достаточно расточительной, но требует меньше ресурсов, чем запоминание объектов Recordset большого объема в переменных сессии и хранение их в период между обращениями к странице. Представьте себе узел с тысячами пользователей, у каждого из которых в переменной сессии хранится объект Recordset. Ресурсы сервера будут моментально истощены.
При помощи ADO можно выполнять доступ к данным на сервере на основе любого оператора SQL. Запросы можно закодировать как хранимые процедуры SQL-сервера или непосредственно в виде SQL-операторов SELECT. Модифицировать данные можно при помощи SQL-операторов UPDATE и метода Execute объекта Connection. ADO может применяться и на клиентской стороне в сочетании с Advanced Data Control (ADC). По сути ADC очень мало отличается от просто ActiveX-оболочки вокруг большей части функциональности ADO. Основную роль в доступе к данным посредством ADC играет его свойство Recordset.
Компонент File Access.Компонент File Access (компонент доступа к файлам) предоставляет доступ к текстовым файлам на Web-узле. На самом деле он состоит из двух отдельных объектов: FileSystem, который служит для открытия и закрытия файлов, и TextStream, предназначенного для чтения и записи.
Итак, чтобы получить доступ к файлу, сначала создайте (методом CreateObject объекта Server) объект FileSystem. Затем для создания нового файла следует вызвать метод CreateTextFile только что созданного объекта, а для открытия существующего файла — метод OpenTextFile. В любом случае оба метода вернут объект TextStream. Ниже показано, как получить доступ к файлу DATA.TXT:
Set objFile = Server. CreateObject("Scripting. FileSystemObject") Set objStream = objFile.OpenTextFile("DATA.TXT")
После создания объекта TextStream можно свободно вызывать любые его методы для чтения или записи информации. Не забывайте, однако, что обычно файл открывается только для чтения или только для записи, но не для того и другого одновременно. Этот факт требует определенной организации кода ASP-страниц: если над одним и тем же файлом необходимо выполнить разные операции, его следует открыть, закрыть и вновь открыть.
Помимо просто чтения и записи компонент File Access служит для создания динамического информационного наполнения. Давайте попробуем реализовать генератор «дежурных советов» (tip-of-the-day), выводящий подсказки или сообщения, которые обновляются при каждой новой загрузке страницы. Полный текст примера, посвященного советам по программированию на Visual Basic, приведен в листинге 4.9. Главное в этой задаче — написать текстовый файл, каждая строчка которого содержит одну подсказку. Затем эти строчки считываются по одной в случайном порядке методом ReadLine объекта TextStream и помещаются на страницу методом Write объекта Response.
Листинг 4.9.Генерация «дежурного совета».
<HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html; charset=windows-1251">
<TITLE>VB Tips</TITLE> </HEAD>
<BODY BGCOLOR="#FFFFFF">
<%
' Объявляем переменные
Dim objFile
Dim objStream
' Открываем файл
Set objFile =Server.CreateObject("Scripting.FileSystemObject")
Set objStream =objFile.OpenTextFile(Server.MapPath("/scripts") &_ "\web\l5\tips.txt")
Randomize Timer
intLine = Int(Rnd * 19)
For i = 0 to intLine
objStream.SkipLine
Next
strText = objStream.ReadLine
objStream.Close
Set objStream = Nothing
Set objFile = Nothing
%>
<CENTER><H1>Дежурный совет по VB</H1></CENTER>
<%=strText%>
</BODY></HTML>
Компонент Browser Capabilities.Компонент Browser Capabilities (компонент характеристик программы просмотра) идентифицирует программу просмотра Web, которая в данный момент осуществляет доступ к узлу, а также предоставляет программный доступ к ряду поддерживаемых этой программой возможностей. Это огромная ценность для Web-разработчиков, которые должны поддерживать как Internet Explorer, так и Netscape Navigator. При помощи этого компонента можно приспособить Web-страницу к определенному типу программы просмотра.
Действие компонента Browser Capabilities основано на строке пользовательского агента программы просмотра, в которой указан тип последней. Эту строку программа просмотра передает серверу каждый раз при запросе Web-страницы. Для IE 4.0 строка выглядит так:
Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)
Чтобы определить, какие возможности поддерживает данная программа просмотра, компонент пытается найти соответствие полученной строке среди образцов в специальном файле инициализации BROWSCAP.INI. Как только такой образец найден, все возможности, свойственные этой программе просмотра, немедленно становятся доступны как свойства компонента характеристик. В листинге 4.10 приведен фрагмент файла BROWSCAP.INI, соответствующий IE 4.0.
Листинг 4.10.Фрагмент файла BROWSCAP.INI для IE 4.0.
Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)
browser=IE
Version=4.0
majorver=#4
minorver=#0
frames=TRUE
tables=TRUE
cookies=TRUE
backgroundsounds=TRUE
vbscript=TRUE
javascript=TRUE
javaapplets=TRUE
ActiveXControls=TRUE
Win16=False
beta=False
Использование компонента Browser Capabilities заменяет в ASP-страницах операторы условной компиляции. Можно построить такие простые операторы If...Then, которые очень заметно влияют на конечный результат. Так, код из листинга 4.11 посылает тег <OBJECT> программе просмотра, поддерживающей элементы управления ActiveX, тег <APPLET> — программе просмотра с поддержкой Java и текстовое сообщение — всем остальным.
Листинг 4.11.Определение характеристик программы просмотра Web.
<%@LANGUAGE="VBScript"%>
<%Response.Expires=-1%>
<HTML><HEAD>
<HETA HTTP-EQUIV="Content-Type" content="text/html; charset=windows-1251">
<TITLE>Browser Capabilities</TITLE> </HEAD> <BODY> <CENTER>
<%
' Создаем компонент Browser Capabilities
Dim objBrowser
Set objBrowser = Server.CreateObject("MSWC.BrowserType")
' Выясняем, какие возможности поддерживаются
If objBrowser.ActiveXControls Then
%>
<H1>Элементы управления ActiveX</H1>
<OBJECT ID="mylabel" WIDTH="300" HEIGHT="51"
CLASSID="CLSID:978C9E23-D4B0-11CE-BF2D-00AA003F40D0"
CODEBASE="http://www.microsoft.com/activex/controls/FM20.DLL">
<PARAM NAME="ForeColor" VALUE="98776">
<PARAM NAME="VariousPropertyBits" VALUE="276824091">
<PARAM NAME="Caption" VALUE="Щелкни меня!">
<PARAM NAME="Size" VALUE="7691;1094">
<PARAM NAME="SpecialEffect" VALUE="1">
<PARAM NAME="FontEffects" VALUE="1073741827">
<PARAM NAME="FontHeight" VALUE="480">
<PARAM NAME="FontCharSet" VALUE="204">
<PARAM NAME="ParagraphAlign" VALUE="3">
<PARAM NAME="FontWeight" VALUE="700">
</OBJECT>
<%ElseIf objBrowser.JavaApplets Then%>
<H1>Апплет Java</H1>
<applet code="marquee.class" codebase="http://inna/scripts/web/l5" align="baseline" HEIGHT=40 WIDTH=400>
<PARAM NAME="CAPTION" VALUE="Java is Cool!">
</APPLET>
<%Else%>
<!-- Чисто текстовая программа просмотра -->
<H1>Никакие компоненты не поддерживаются!</Н1>
<%End If%>
</CENTER> </BODY> </HTML>
Компонент Ad Rotator.Компонент Ad Rotator (ротация рекламных объявлений) специально предназначен для узлов, продающих рекламную площадь. Он позволяет управлять ротацией рекламных картинок на узле. Ad Rotator считывает информацию о рекламных объявлениях из специального текстового файла и указывает, какое объявление следует показывать и как долго. Использование данного компонента сводится к его созданию и чтению текстового файла, как в следующем фрагменте кода:
<%
Dim Ad
Set Ad = Server.CreateObject("MSWC.AdRotator")
Response.Write Ad.GetAdvertisement("ADS.TXT")
%>
Файл, считываемый компонентом Ad Rotator, имеет четко заданную структуру, которая определяет, какое изображение выводить и какую часть времени его показывать, а также обеспечивает гипертекстовую ссылку, активизируемую при щелчке данного объявления. От Вас требуется только составить текстовый файл определенного формата, а компонент сделает все остальное.
Компонент Content Linking.Компонент Content Linking (компонент связывания содержания) предназначен для публикаций электронных журналов и газет. Он связывает вместе несколько Web-страниц, позволяя их прокручивать. Как и Ad Rotator, компонент Content Linking для создания публикации использует текстовый файл. Этот файл, известный как список информационных ссылок (Content Linking List), содержит список связанных Web-страниц и их описаний. Использование данного компонента сводится к его созданию и последующему считыванию ассоциированного текстового файла, как в следующем фрагменте кода:
<%Set objLinker = Server.CreateObject("MSWC.NextLink")%>
Когда публикация скомпонована, для перемещения по страницам используются методы GetNextURL и GetPreviousURL, а описания каждой конкретной страницы можно получить, вызвав методы GetNextDescription и GetPreviousDescription. Полученные значения служат для генерации ссылок на другие страницы публикации. Пример такой ссылки:
<А HREF="<%=objLinker.GetNextURL%>">
<%=objLinker.GetNextDescriptiion%> </A>
Использование других компонентов ActiveX.Кроме использования компонентов, поставляемых с Visual InterDev, Вы можете создавать свои собственные компоненты ActiveX для ASP. Когда такой компонент разработан, работать с ним можно посредством метода CreateObject объекта Server. Все, что нужно - это указать его ProgID.
Написание собственных компонентов позволяет расширить возможности ASP.
Доступ к базам данных.
Хотя доступ к базам данных средствами ADO уже обсуждался, уделим еще некоторое время этому вопросу. Дело в том, что приведенные ранее примеры работоспособны, только если на сервере создан источник данных ODBC. Его создание обычно производится апплетом Панели управления Windows, который при удаленной работе с сервером оказывается недоступен. Для выхода из этой ситуации применяют файловый DSN (Data Source Name), создав который, можно скопировать файл с расширением .dsn в тот же каталог, что и сценарий, обращающийся к базе данных. В листинге 4.12 приведен пример файла для доступа к базе данных MS Access, а в листинге 4.13 - для доступа к БД MySQL.
Листинг 4.12.Файл для доступа к БД MS Access'97.
[ODBC]
DRIVER=Microsoft Access Driver (*.mdb)
UID=admin
UserCommitSync=Yes
Threads=3
SafeTransactions=0
ReadOnly=0
PageTimeout=5
MaxScanRows=8
MaxBufferSize=512
ImplicitCommitSync=Yes
FIL=MS Access
DriverId=281
DefaultDir=C:\Inetpub\scripts\bookcd
DBQ=C:\Inetpub\scripts\bookcd\bakal1.mdb
Сценарий, использующий этот файл, приведен в листинге 4.14.
Листинг 4.13.Файл для доступа к БД MySQL.
[ODBC]
DRIVER=MySQL ODBC 3.51 Driver
UID=gun
STMT=
OPTION=3
PORT=
PASSWORD=
SERVER=inna
DATABASE=test
Листинг 4.14.Сценарий формирования DSN.
<%
Dim sDB, sPath, sDSNFil, sDSN, sScriptDir
'This is the entire DB path
sDB = "C:\Inetpub\scripts\bookcd\bakal1.mdb"
' Retrieve the script directory
sScriptDir = Request.ServerVariables("SCRIPT_NAME")
sScriptDir = StrReverse(sScriptDir)
sScriptDir = Mid(sScriptDir, InStr(1, sScriptDir, "/"))
sScriptDir = StrReverse(sScriptDir)
' Set the virtual Directory
sPath = Server.MapPath(sScriptDir) & "\"
' This is the DSN file Name for Access database
sDSNFil = "Access.dsn" ' This is the resulting DSN string
sDSN="filedsn="&sPath&sDSNFil&";DefaultDir="&sPath&";DBQ="&sPath&sDB&";"
%>
Чтобы не вставлять данный код в каждый сценарий, в котором требуется обращение к базе данных, применяют файлы включения (подобно include-файлам в языке С):
<!-- #include file ="dsn.asp" -->
<!-- #include file="adovbs.inc" -->
Заметим, что файл adovbs.inc не может быть вызван, как сценарий, хотя и содержит код. Как правило, в файлы с расширением .inc помещают часто употребляемые константы и функции, как это показано в листинге 4.15:
Листинг 4.15.Файл включения.
<%
' ADO constants include file for VBScript
'---- CursorTypeEnum Values ----
Const adOpenForwardOnly = 0
Const adOpenKeyset = 1
Const adOpenDynamic = 2
Const adOpenStatic = 3
%>
<FONT FACE="Verdana, Arial" SIZE=2>
<FORM ACTION="<% =sScript%>" METHOD=GET>
<SELECT NAME=YEAR>
<OPTION VALUE=1998 SELECTED>1998
<OPTION VALUE=1999>1999
<OPTION VALUE=2000>2000
<OPTION VALUE=2001>2001
<OPTION VALUE=2002>2002
</SELECT></FONT>
<P><INPUT TYPE="Image" SRC="images/go.gif" BORDER="0" WIDTH="35" HEIGHT="20"> </P>
</FORM>
В заключение приведем в листинге 4.16 законченный пример сценария авторизации посетителя с извлечением регистрационного имени и пароля из базы данных.
Листинг 4.16.Сценарий авторизации посетителя.
<!-- #include file ="dsn.asp" -->
<!-- #include file="adovbs.inc" -->
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Идентификация пользователя</title></head>
<body BGCOLOR="#CCCCFF" TEXT="#0000FF" LEFTMARGIN="3">
<%
If not isEmpty(Session("userlevel")) then
Session("userlevel") = Empty
Session("userid") = Empty
end if
user = Request.Form.Item("T1")
pswd = Request.Form.Item("T2")
b1 = Request.Form.Item("B1")
If not isEmpty(user) and not isEmpty(pswd) then
Set Rs = Server.CreateObject("ADODB.RecordSet")
sSQL = "SELECT Users.Pswd, Users.Access_ID, Users.User_ID FROM Users WHERE Users.Login = '"&user&"'"
Rs.Open sSQL, sDSN
if not RS.EOF then
if RS.fields(0).value = pswd then
Session("userlevel") = RS.fields(1).value
Session("userid") = RS.fields(2).value
Response.Redirect("menu.asp")
end if
end if
Session("userlevel") = 3
Response.Redirect("menu.asp")
end if
%>
<form method="POST" action="enter.asp">
<center>
<table border="0" width="50%" cellspacing="1" cellpadding="4">
<tr><td width="100%" colspan="2" bgcolor="#000080">
<b><font size="4">Идентификация пользователя </font> </b></td> </tr>
<tr><td width="50%" align="right">Имя:</td>
<td width="50%"><input type="text" name="T1" size="20"></td>
</tr>
<tr><td width="50%" align="right">Пароль:</td>
<td width="50%"><input type="password" name="T2" size="20"></td>
</tr>
<tr><td width="100%" align="right" colspan="2">
<center><input type="submit" value="Войти" name="B1" ></td>
</tr>
</table></center>
</form></body></html>
Доступ к базам данных MySQL осуществляется аналогично, с использованием файлового источника данных (листинг 4.13) и модификации сценария доступа (листинг 4.14), где последняя строка имеет вид:
sDSN = "filedsn=" & sPath & sDSNFil & ";"
Ниже приводится аналог листинга 4.10, но обращающегося к базе данных MySQL (из примера 3.14).
Листинг 4.17.Сценарий доступа к БД MySQL.
<%@ LANGUAGE="VBScript"%>
<!-- #include file ="e14a.asp" -->
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html; charset=windows-1251">
<TITLE>Using MySQL</TITLE></HEAD><BODY>
<%
Dim objRecordset
Set objRecordset = Server.CreateObject("ADODB.Recordset")
' Устанавливаем подсоединение и выполняем запрос
objRecordset.Open "SELECT name FROM people", sDSN
%><!-- Строим список SELECT по набору данных -->
<SELECT SIZE=3>
<% Do While Not ObjRecordset.EOF %>
<!-- Создаем очередной элемент списка -->
<OPTION><%=objRecordset("name")%></OPTION>
<% objRecordset.MoveNext
Loop %>
</SELECT></BODY></HTML>