ЛАБОРАТОРНАЯ РАБОТА 3 ИСПОЛЬЗОВАНИЕ ТЕХНОЛОГИИ AJAX ПРИ ПРОГРАММИРОВАНИИ WEB-ПРИЛОЖЕНИЙ 1. Цель работы Целью работы является изучение технологии AJAX при программировании Webприложений. 2. Задачи Задачами лабораторной работы являются овладение навыками создания связанных элементов управления на Web-странице приложения, использования объекта XmlHttpRequest, использования асинхронных запросов к серверу. 3. Теоретическая часть Традиционное веб-программирование. Классическая модель веб-приложения действует следующим образом: большинство действий пользователя отправляют обратно на сервер HTTP-запрос. Сервер производит необходимую обработку – получает данные, обрабатывает числа, взаимодействует с различными унаследованными системами и затем выдает HTML страницу клиенту. Все это время пользователю не только приходится ожидать ответов от сервера, но и для каждой пары «запрос/ответ» страница перерисовывается заново. Таким образом, веб-сервер отвечает на каждый запрос, возвращая совершенно новую страницу HTML с обновленными данными, а весь процесс повторяется снова и снова. Кроме того, в традиционном веб-программировании все сведения, связанные со страницей, и элементы управления на странице теряются при каждом цикле обработки. Например, если пользователь ввел сведения в текстовое поле, то эти сведения будут потеряны в ходе цикла обработки от веб-обозревателя или клиентского устройства к серверу. AJAX. Ajax – принципиально новый подход к веб-программированию. Расшифровывается AJAX как Asynchronous JavaScript and XML (Асинхронный JavaScript и XML). Веб-страница отправляет запросы с помощью функции JavaScript, обеспечивающей взаимодействие с сервером. Для веб-сервера ничего не изменилось – он по-прежнему отвечает на каждый запрос. Однако ответ сервера содержит только данные, необходимые для страницы без разметки и представления. Большая часть страницы остается неизменной, обновляются только части, которые должны быть изменены. JavaScript динамически обновляет веб-страницу без перерисовки. Простыми словами можно сформулировать так: AJAX – это когда с помощью JavaScript можно запрашивать и получать данные с сервера, не перезагружая станицу сайта. Несмотря на то, что в названии технологии явным образом присутствует слово «XML», сервер может возвращать свой ответ не только в XML-формате, но и в более привычном текстовом виде. Главное отличие в том, что web-страница, созданная с помощью AJAX, может взаимодействовать с web-сервером в «асинхронном» режиме, запрашивая и получая данные без необходимости обновления страницы в браузере. Обычная web-страница для обмена данными с сервером должна быть обновлена целиком. Например, отправка данных web-формы на сервер и отображение ответа происходят на разных web-страницах: первая содержит данные формы, а вторая генерируется сервером в ответ на запрос браузера. Такая технология требует от браузера дополнительного сетевого трафика и времени, затрачиваемого на отображение страницы. К тому же web-сервер даже при минимальных отличиях между двумя web-страницами часто вынужден передавать большие объемы информации при загрузке каждой из них. AJAX же позволяет обновлять лишь те фрагменты web-страницы, которые действительно изменялись, не перезагружая страницу целиком. При этом браузер обменивается данными со сценарием на web-сервере, передавая минимальную информацию – только то, что нужно. AJAX позволяет делать запросы к серверу асинхронными. Термин «асинхронность» означает, что во время обработки запроса пользователь может продолжить работу с приложением. Объект XMLHTTPRequest. Объект XMLHttpRequest дает возможность браузеру делать HTTP-запросы к серверу без перезагрузки страницы. В разных браузерах этот объект создается разными способами. Так, к примеру, в браузерах Safari, Firefox, Mozilla и большинстве альтернативных браузеров этот объект называется XMLHttpRequest, в Internet Explorer – это объект ActiveX «Msxml2.XMLHTTP», в других браузерах Microsoft – это объект ActiveX «Microsoft.XMLHTTP». Отправка запросов с помощью объекта XMLHttpRequest выполняется с помощью трех основных методов: – open(Method, Url, async) – инициализация подключения: Method – HTTP-метод (POST или GET); Url – URL сценария, работающего на веб-сервере (куда направляется этот запрос); async – вид подключения (true, если подключение асинхронное, false, если подключение синхронное). – send(data) – параметры отправки запроса. Обычно в качестве параметра этому методу передается значение null, т. е. без данных; – onreadystatechange – функция обратного вызова, т. е. название той JavaScriptфункции, которая должна быть вызвана при получении ответа от сервера. Данные, полученные в результате запроса к серверному сценарию, могут быть представлены как в форме текста (свойство ResponseText), так и в виде XML-разметки (свойство ResponseXml). JavaScript. JavaScript может использоваться как для синхронных, так и для асинхронных запросов к серверу. Обработчики событий JavaScript позволяют организовать вызов кода JavaScript при выполнении различных условий. Типичные примеры – onClick() и onChange(). Ajax по существу помещает технологию JavaScript и объект XMLHttpRequest между Web-формой и сервером. Когда пользователи заполняют формы, данные передаются в какой-то JavaScript-код, а не прямо на сервер. JavaScript-код собирает данные формы и передает запрос на сервер. Пока это происходит, форма на экране пользователя не мелькает, не мигает, не исчезает и не блокируется (если запрос асинхронный). Другими словами, код JavaScript передает запрос в фоновом режиме. Пользователи могут продолжать вводить данные, прокручивать страницу и работать с приложением. Затем сервер передает данные обратно в JavaScript-код (все еще находящийся в Webформе), который решает, что делать с данными. К примеру, он может обновить поля формы "на лету", пользователи получают новые данные без подтверждения или обновления их форм. JavaScript-код может даже получить данные, выполнить какие-либо вычисления и передать еще один запрос. Браузер. Именно браузер выполняет код JavaScript, незаметно для пользователя он производит такие важные операции, как сохранение значений переменных, создание новых типов и обработка сетевых запросов, которые могли быть выданы вашим кодом. Браузер организует передачу запросов веб-серверу и разбирается, что делать с ответами, полученными от этих серверов. Но это вовсе не означает, что запросы серверу передает браузер, а не код. Он просто поддерживает такую передачу, организует низкоуровневые сетевые протоколы, обеспечивающие работу этого кода. Состояние готовности запроса. Состояние готовности запроса определяет, на какой стадии находится его обработка: запрос инициализируется, установлена связь с сервером, сервер завершил обработку и т. д. Выделяются следующие значения состояний: 0 – подключение не инициализировано при загрузке веб-страницы создается новый объект запроса; 1 – подключение инициализировано – после инициализации подключения запрос отправляется серверу; 2 – в процессе обработки запроса – сервер передает запрос нужному сценарию или программе, и эта программа отвечает на запрос; 3 – получение ответа сервера – на этой стадии браузер делает доступным код состояния и заголовки запроса, полученные от сервера; 4 – ответ сервера готов – сервер завершил обработку: все данные доступны в свойстве responseText объекта запроса. Статус запроса. Состояние готовности запроса указывает браузеру, на какой стадии находится обработка запроса: инициализация, обработка, завершение и т. д. Однако сам факт завершения еще не означает, что запрос завершился успешно. За это отвечает статус запроса. Статус указывает, что произошло во время запроса, и развивались ли события именно так, как предполагалось. Работает статус следующим образом. Объект запроса XMLHttpRequest отправляет запрос веб-серверу вместе с URL сценария, который должен его обработать. Сервер определяет, какой код статуса он должен вернуть. Если программа успешно обработала запрос, возвращается статус 200. Если сервер не может найти программу, указанную в URL, он возвращает код статуса 404. Статус возвращает код состояния и код статуса на основании того, удалось ли найти запрашиваемый ресурс, и какие данные были получены от этого ресурса. Завершив обработку запроса, сервер возвращает код статуса и состояние готовности 4. Функция обратного вызова. Функция обратного вызова – это та функция, которая запускается браузером при изменении состояния запросов. Она запускается каждый раз, когда с запросом что-то происходит, а не только при получении ответа. Иначе говоря, функция обратного вызова вызывается несколько раз: при переходе состояния готовности с 1 на 2, при следующем переходе с 2 на 3, и в последний раз при переходе с 3 на 4. Однако сервер гарантирует наличие данных, пригодных для использования, только в состоянии готовности 4. А это означает, что текущее состояние готовности должно проверяться перед обновлением соответствующей части веб-страницы, потому что в противном случае страница может содержать неполные или недействительные данные. Если проверка показывает, что обработка запроса завершена, необходимо убедиться в отсутствии ошибок; эта информация хранится в коде статуса. Чтобы быть уверенным в том, что запрос был обработан, а страницу можно обновлять данными, полученными от сервера, необходимо как состояние готовности, так и статус. Значит, состояние готовности должно быть равно 4 (что означает, что запрос был полностью обработан), а статус должен быть равен 200 (который указывает на отсутствие ошибок). Модель DOM. Для представления кода HTML, образующего веб-страницу, браузер использует модель дерева объектов Document Object Model (DOM). DOM работает с Ajax, но DOM не является частью Ajax. Для просмотра и модификации модели DOM используется код JavaScript. Изменения, вносимые в DOM, автоматически воспроизводятся на веб-странице, отображаемой браузером. При внесении любых изменений в модель веб-страницы браузер автоматически обновляет отображаемую страницу. AJAX в PHP и JSP. В веб-приложениях PHP и JSP технология AJAX используется одинаково. Создается JavaScript-сценарий (в самом веб-приложении или в отдельном файле), в нем программируется создание экземпляров объекта XmlHttpRequest и функции обратного вызова, которые выполняются при получении ответа на запрос от сервера. AJAX в ASP.NET. Приложения ASP.NET реализуют AJAX-функциональность как с помощью традиционных объектов XmlHttpRequest, так и более «продвинутым» способом с помощью элементов управления, предоставляемых надстройкой Ajax Control Toolkit. В лабораторной работе рассматриваются оба этих способа. Использование объектов XmlHttpRequest в приложениях ASP.NET выполняется точно так же, как и в PHP- и JSP-приложениях – с помощью соответствующих JavaScriptсценариев. Надстройка Ajax Control Toolkit содержит более 40 элементов управления, таких как CollapsiblePanel, ColorPicker, MaskedEdit, Calendar, Cascading Dropdown и др. С помощью Ajax Control Toolkit можно построить веб-формы ASP.NET с использованием AJAX (Ajaxenabled ASP.NET Web Forms). Достаточно просто перетащить элементы управления с панели инструментов Visual Studio Toolbox на страницу Web-форму. 4. Порядок выполнения работы Предварительные замечания В лабораторной работе нужно связать три раскрывающихся списка (факультетов, специальностей и групп), расположенных на странице Index.php. При выборе значения из списка факультетов в списках специальностей и групп должны остаться только те значения, которые соответствуют выбранному факультету. При выборе значения специальности из списка специальностей должен быть отфильтрован список групп – остаются только те группы, которые относятся к выбранной специальности. Вариант А. Технология ASP.NET и СУБД Microsoft SQL Server А1. Объекты XMLHttpRequest 1. Создать новый Web-сайт: Пуск | Microsoft Visual Studio 2005 | Microsoft Visual Studio 2005 ф. Microsoft Visual Studio | File → New → Web Site… → ф. New Web Site → Visual Studio Installed Templates → выбр. ASP.NET Web Site → Location → выбр. HTTP → http://имя_сервера(например, localhost)/Lab1_ASP Language → выбр. Visual C# 2. Перейти на страницу ввода программного кода: ф. Lab1_ASP → Default.aspx → Source | удалить весь код, расположенный между открывающим и закрывающим тегами элемента BODY 3. Задать заголовок страницы Default.aspx. Для этого между открывающим и закрывающим тегами элемента HEAD ввести следующий код: <TITLE>Успеваемость студентов</TITLE> 4. Подключить библиотеки для работы с базами данных (System.Data, System.Data.SqlTypes, System.Data.SqlClient). Для этого после строки программного кода <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"%> добавить следующие строки: <%@Import Namespace="System.Data"%> <%@Import Namespace="System.Data.SqlTypes"%> <%@Import Namespace="System.Data.SqlClient"%> 5. Создать серверную функцию Page_Load, выполняемую при загрузке страницы: void Page_Load(object sender, EventArgs e) { 5.1 Проверить, загружается ли форма в первый раз или она должна формироваться как результат обработки данных, введенных пользователем: if (!Page.IsPostBack) { 5.2 Если форма загружается в первый раз, задать элементу faculty (раскрывающийся список факультетов) обработчик события onchange (изменение выбранного значения) – функцию startRequest: this.faculty.Attributes.Add("onchange", "return startRequest();"); 5.3 Вызвать функцию ListFaculty, формирующую список факультетов, полученный из базы данных: ListFaculty(); 5.4 Проверить, присвоено ли значение переменной facultyID. Если это условие выполняется, то вызвать функцию GetSpecByFacultyID (формирование списка специальностей факультета) и передать ей в качестве параметра значение facultyID: if (facultyID != "") { GetSpecByFacultyID(facultyID); } 5.5 Проверить, присвоено ли значение переменной specID. Если значение присвоено, то вызвать функцию GetGrBySpecID (формирование списка групп специальности) и передать ей в качестве параметра значение specID: if (specID != "") { GetGrBySpecID(specID); } } } 6. Создать строковую переменную facultyID: private string facultyID { 6.1 Объявить метод GET получения значения переменной: get { 6.2 Проверить, был ли передан странице параметр facultyID и содержит ли он какое-нибудь значение: if (Request["facultyID"] != null && Request["facultyID"].ToString() != "") 6.3 Если значение facultyID передано, то вернуть его: { return Request["facultyID"]; } 6.4 В противном случае вернуть пустую строку: else { return ""; } } } 7. Аналогичным образом создать строковую переменную specID: private string specID { get { if (Request["specID"] != null && Request["specID"].ToString() != "") { return Request["specID"]; } else { return ""; } } } 8. Создать функцию GetSpecByFacultyID с входным строковым параметром facultyID – формирование списка специальностей (элемента select). 8.1 Ввести имя функции и объявить входной параметр : private void GetSpecByFacultyID(string facultyID) { 8.2 Создать строковую переменную connStr и записать в нее параметры соединения с базой данных: string connStr = "Data Source=имя_компьютера;Initial Catalog=University;Integrated Security=True"; 8.3 Соединиться с базой данных University: SqlConnection conn = new SqlConnection(connStr); 8.4 Создать строковую переменную sql и записать в нее текст SQL-запроса формирования списка специальностей, соответствующих факультету, код которого размещается в переменной facultyID: string sql = "select '0' as id, 'Выбор специальности...' as name from Speciality union select id, name from Speciality where faculty='" + facultyID + "'"; 8.5 Выполнить запрос и занести результат в экземпляр объекта SqlDataReader: SqlCommand cmd = new SqlCommand(sql, conn); conn.Open(); SqlDataReader dr = cmd.ExecuteReader(); 8.6 Создать строковую переменную s и записать в нее разметку открывающего тега элемента SELECT. Указать, что элемент является серверным, и задать стиль его представления. Задать выражение, присваивающее выбранное значение списка элементу с ID="spec": string s = "<select runat='server' style='width: 350px' onChange=\"javascript:document.getElementById('spec').value=this.value;return startRequest2();\">"; 8.7 Задать цикл по результату запроса: while (dr.Read()) { 8.8 Сформировать элементы списка SELECT. В качестве значения для каждого элемента списка указать значение поля id, в качестве отображаемого текста – значение поля name: s += "<option value='" + dr["id"] + "'>" + dr["name"] + "</option>"; } 8.9 Добавить к содержимому переменной s разметку закрывающего тега элемента SELECT: s += "</select>"; 8.10 Закрыть экземпляр объекта SqlDataReader и соединение с базой данных: dr.Close(); conn.Close(); 8.11 Вывести в поток значение переменной s: this.Response.Write(s); this.Response.End(); } 9. Аналогичным образом создать функцию GetGrBySpecID с входным параметром specID – формирование списка групп заданной специальности. 10. Создать функцию ListFaculty – формирование списка факультетов и заполнение раскрывающегося списка с идентификатором faculty 10.1 Задать имя функции: private void ListFaculty() { 10.2 В строковую переменную sql занести код запроса, извлекающего список факультетов из базы данных: string sql = "select '0' as id, 'Выбор факультета...' as name from Faculty union select * from Faculty"; 10.3 Установить соединение с базой данных и выполнить запрос к ней: string constring = "Data Source=имя_компьютера;Initial Catalog=University;Integrated Security=True"; SqlDataAdapter sda = new SqlDataAdapter(sql, constring); 10.4 Создать экземпляр объекта DataSet и заполнить его результатом запроса: DataSet ds = new DataSet(); sda.Fill(ds); 10.5 Заполнить список faculty значениями объекта DataSet: faculty.DataSource = ds; faculty.DataTextField = "name"; faculty.DataValueField = "id"; faculty.DataBind(); } 11. Скопировать содержимое файла Index.aspx из лабораторной работы 1, начиная с открывающего тега элемента html и заканчивая соответствующим закрывающим тегом. 12. Заменить идентификатор элемента spec на любое другое значение, к примеру, DropDownList1. Поместить полученный элемент между открывающим и закрывающим тегами элемента DIV с ID=" gridiv " <div id="gridiv">…</div> 13. Заменить идентификатор элемента gr на другое значение, например, groups. Поместить полученный элемент между открывающим и закрывающим тегами элемента DIV с ID=" div_gr " <div id="div_gr">…</div> 13. Создать два скрытых элемента spec и groups: <asp:HiddenField ID="spec" runat="server"/> <asp:HiddenField ID="gr" runat="server"/> 14. Создать клиентский сценарий JavaScript, создающий и использующий объект XMLHttpRequest 14.1 Ввести открывающий тег сценария: <script type="text/javascript"> 14.2 Создать переменную xmlHttp для хранения экземпляра объекта XMLHttpRequest: var xmlHttp; 14.3 Создать функцию createXMLHttpRequest, формирующую экземпляр объекта XMLHttpRequest для различных типов браузеров: function createXMLHttpRequest() { if (window.ActiveXObject) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } } 14.4 Создать функцию startRequest формирования запроса на основе объекта XMLHttpRequest. function startRequest() { 14.4.1 Создать переменную facultyID и присвоить ей значение, выбранное в раскрывающемся списке faculty: var facultyID=document.getElementById('faculty').value; 14.4.2 Создать экземпляр объекта XMLHttpRequest: createXMLHttpRequest(); 14.4.3 Задать функцию обратного вызова handleStateChange: xmlHttp.onreadystatechange = handleStateChange; 14.4.4 Определить параметры запроса информации о специальностях по коду факультета (facultyID): xmlHttp.open("GET", "?facultyID="+facultyID, true); xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"); xmlHttp.send(null); } 14.5 Создать функцию обратного вызова handleStateChange: function handleStateChange() { 14.5.1 Проверить состояние готовности запроса («4» – запрос выполнен) if(xmlHttp.readyState == 4) { 14.5.2 Проверить статус запроса («200» – запрос выполнен успешно) if(xmlHttp.status = = 200) { 14.5.3 Заменить содержимое DIV-элемента gridiv на HTML-код, полученный в результате выполнения запроса: document.getElementById("gridiv").innerHTML=xmlHttp.responseText; } } } 14.6 Аналогичным образом (см. пп. 14.4–14.5) настроить запрос XmlHTTPRequest на получение информации о группах по значению кода специальности: function startRequest2() { var facultyID=document.getElementById('spec').value; createXMLHttpRequest(); xmlHttp.onreadystatechange = handleStateChange2; xmlHttp.open("GET", "?specID="+facultyID, true); xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"); xmlHttp.send(null); } function handleStateChange2() { if(xmlHttp.readyState == 4) { if(xmlHttp.status == 200) { document.getElementById("div_gr").innerHTML=xmlHttp.responseText; } } } 14.7 Ввести закрывающий тег сценария: </script> 15. Проверить работоспособность созданного Web-приложения. Для этого перейти на страницу Lab3_ASP - Microsoft Visual Studio | Default.aspx и нажать сочетание клавиш [Ctrl+F5]. А2. Библиотека AJAX ASP.NET Toolkit 1. Создать новый Web-сайт: Пуск | Microsoft Visual Studio 2005 | Microsoft Visual Studio 2005 ф. Microsoft Visual Studio | File → New → Web Site… → ф. New Web Site → Visual Studio Installed Templates → выбр. ASP.NET AJAX-Enabled Web Site→ Location → выбр. HTTP → http://имя_сервера(например, localhost)/Lab3_ASP Language → выбр. Visual C# На странице Default.aspx должна появиться следующая строка: <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %> Если строка не появилась, то добавить ее вручную. 2. Добавить библиотеку компонентов AJAX ASP.NET Toolkit Ф. Toolbox | пр. кн. мыши | выбр. Add Tab | ввести текст «AJAX Control Toolkit» Вкл. AJAX Control Toolkit | пр. кн. мыши → Choose Items... Ф. Choose toolbox items… | кн. Browse → выбр. файл AjaxControlToolkit.dll → кн. OK 3. Перейти на страницу ввода программного кода: ф. Lab3_ASP → Default.aspx → Source | удалить весь код, расположенный между открывающим и закрывающим тегами элемента BODY 4. Скопировать весь код, размещенный между открывающим и закрывающим тегами BODY (включая сами эти теги), из файла Index.aspx первой лабораторной работы. 5. Ввести элемент ScriptManager: <asp:ScriptManager ID="ScriptManager1" runat="server" /> 6. Создать Web-сервис, содержащий методы извлечения из базы данных информации о факультетах, специальностях, группах и успеваемости студентов. 6.1 Создать Web-сервис University.asmx Ф. Solution Explorer | пр. кн. мыши Add New Item… Ф. Add New Item → выбр. ASP.NET Web Service → Name → University.asmx | выбр. Place code in separate file Language → выбр. Visual C# | кн. OK 6.2 Для работы с базами данных, массивами и списками значений, AJAX-компонентами подключить следующие библиотеки классов: using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using AjaxControlToolkit; 6.2 Создать Web-метод GetSpecsByFacultyId получения данных о специальностях по коду факультета (входной параметр метода – код факультета (переменная faculties)). Переменная faculties содержит значения идентификаторов факультетов из элемента CascadingDropDown, разделенные символом « ; »: [System.Web.Services.WebMethod] [System.Web.Script.Services.ScriptMethod] public CascadingDropDownNameValue[] GetSpecsByFacultyId(string faculties) { 6.3 Создать строковый массив _ faculties, получаемый из выделения подстрок методом Split, которому в качестве символов-разделителей передаются « : » и « ; »: string[] _ faculties = faculties.Split(':', ';'); 6.4 Определить выбранное в раскрывающемся списке факультетов значение facultyID. Оно второе в массиве _ faculties: string facultyID = _ faculties [1]; 6.5 Создать список значений _specs для хранения данных о специальностях, полученных в результате выполнения запроса: List<CascadingDropDownNameValue> _specs = new List<CascadingDropDownNameValue>(); 6.6 Создать строковую переменную sql и записать в нее SQL-код запроса на получение данных о специальностях по коду факультета: string sql = "select '0' as id, 'Выбор специальности...' as name from Speciality union select id, name from Speciality where faculty='" + facultyID + "'"; ; 6.7 Создать строковую переменную constring и записать в нее параметры соединения с базой данных University: string constring = "Data Source=имя_сервера;Initial Catalog=University;Integrated Security=True"; 6.8 Создать экземпляр класса SqlDataAdapter и в качестве параметров передать ему запрос на получение данных и параметры соединения: SqlDataAdapter sda = new SqlDataAdapter(sql, constring); 6.9 Записать результат запроса в экземпляр класса DataTable: DataTable dt = new DataTable(); sda.Fill(dt); 6.10 В цикле по записям результата запроса заполнить соответствующий список специальностей класса CascadingDropDownList: foreach (DataRow _r in dt.Rows) { _specs.Add(new CascadingDropDownNameValue(_r["name"].ToString(), _r["id"].ToString())); } 6.11 Вернуть полученный список специальностей: return _specs.ToArray(); } 6.12 Аналогичным образом создать Web-метод GetGrsBySpecID, формирующий список групп по идентификатору специальности. 7. Вернуться к файлу Index.aspx. 8. Определить заполнение списка факультетов информацией из базы данных при загрузке страницы. 8.1 Задать область ввода сценария на С#: <script language="C#" runat="server"> </script> 8.2 Создать обработчик события загрузки страницы. Для этого между открывающим и закрывающим тегами script ввести следующий код: void Page_Load(object sender, EventArgs e) { } 8.3 Создать строковую переменную sql и записать в нее текст запроса к базе данных на извлечение информации о факультетах. Для этого между открывающей и закрывающей фигурными скобками (п. 8.2) ввести следующий код: string sql = "select '0' as id, 'Выбор факультета...' as name from Faculty union select * from Faculty"; 8.4 Создать строковую переменную constring и записать в нее параметры соединения с базой данных University string constring = "Data Source=имя_сервера;Initial Catalog=University;Integrated Security=True"; 8.5 Создать адаптер данных (экземпляр класса SqlDataAdapter) для выполнения запроса к базе данных: SqlDataAdapter sda = new SqlDataAdapter(sql, constring); 8.6 Определить экземпляр класса DataSet и заполнить его данными из объекта SqlDataAdapter: DataSet ds = new DataSet(); sda.Fill(ds); 8.7 Заполнить раскрывающийся список факультетов (элемент управления с ID="faculty") данными из объекта DataSet: faculty.DataSource = ds; faculty.DataTextField = "name"; faculty.DataValueField = "id"; faculty.DataBind(); 9. Задать элемент CascadingDropDown, формирующий список специальностей в зависимости от выбранного значения факультета. Для этого в любой позиции между открывающим и закрывающим тегами BODY ввести следующий код: <ajaxToolkit:CascadingDropDown ID=" updateSpec" runat="server" Category="Specs" LoadingText="Список загружается..." ParentControlID="faculty" TargetControlID="spec" ServicePath="University.asmx" ServiceMethod="GetSpecsByFacultyId" /> Здесь ID="updateSpec" – идентификатор элемента управления; runat="server" – указание на то, что элемент является серверным; Category="Specs" – категория значений; LoadingText="Список загружается..." – текст, который будет видеть пользователь, пока выполняется запрос и происходит загрузка списка; ParentControlID="faculty" – «родительский» элемент, т. е. такой раскрывающийся список, на основании которого выполняется запрос к серверу; TargetControlID="spec" – «дочерний» (зависимый) элемент, т. е. тот раскрывающийся список, значения которого формируются на основании значения, выбранного в родительском элементе; ServicePath="University.asmx" – используемый Web-сервис (здесь указывается относительный путь, потому что Web-сервис был определен в той же папке, что и приложение); ServiceMethod="GetSpecsByFacultyId" – метод Web-сервиса, который используется для заполнения дочернего раскрывающегося списка. 10. Аналогичным образом создать элемент CascadingDropDown, формирующий список групп в зависимости от выбранного значения специальности через метод GetGrsBySpecID Web-сервиса University.asmx. 11. Скопировать в папку с приложением файл Browse.aspx. 12. Проверить работоспособность созданного Web-приложения. Для этого перейти на страницу Lab3_ASP - Microsoft Visual Studio | Default.aspx и нажать сочетание клавиш [Ctrl+F5]. Вариант Б. Технология PHP и СУБД MySQL 1. Создать папку, в которой будут размещены все файлы Web-приложения, и назвать ее, к примеру, Lab3_PHP. 2. Скопировать файлы Index.php и Browse.php из первой лабораторной работы в папку Lab3_PHP. 3. В текстовом редакторе (например, в «Блокноте») создать новый файл и сохранить его под именем GetSpecGr.php. 4. Ввести открывающий тег PHP-сценария <?php 5. Установить соединение с базой данных MySQL University 5.1 Задать объект link соединения с базой данных $link = @mysql_connect("localhost", "root") or die("Невозможно соединиться с сервером"); 5.2 Выбрать базу данных University $db=@mysql_select_db("university") or die("Нет такой базы данных"); 5.3 Установить кириллическую кодировку (cp-1251) для корректной передачи и получения данных из базы данных. Для этого в сценарий PHP из предыдущего пункта ввести следующий код: @mysql_query("SET SESSION character_set_results = cp1251;"); @mysql_query("SET SESSION Character_set_client = cp1251;"); @mysql_query("SET SESSION Character_set_results = cp1251;"); @mysql_query("SET SESSION Collation_connection = cp1251_general_ci;"); @mysql_query("SET SESSION Character_set_connection = cp1251;"); 6. Создать переменную faculty и записать в нее значения параметра faculty, переданного со страницы Index.php: $faculty = $_GET['faculty']; 7. Создать переменную sp_query для хранения текста запроса к базе данных, для извлечения информации о специальностях факультета, заданного переменной faculty группы: $sp_query="select * from `speciality` where `faculty`=' ".$faculty." ' "; 8. Выполнить запрос к базе данных: $sp=mysql_query($sp_query); 9. Создать переменную specOptions для хранения HTML-разметки элементов options элемента select с идентификатором spec (раскрывающийся список специальностей). Ввести первый элемент списка со значением 0 и отображаемым текстом «Выберите специальность» $specOptions = '<option value="0">Выберите специальность</option>'; 10. В цикле сформировать оставшиеся элементы списка на основании запроса sp. В качестве значения элемента списка использовать код специальности (поле ID), а отображаемый в списке текст – название специальности (поле name). while ( $spec = mysql_fetch_array( $sp ) ) { $specOptions = $specOptions.'<option value="'.$spec['ID'].'">'.$spec['name'].'</option>'; } 11. Аналогичным образом создать запрос на извлечение данных о группах заданного факультета (текст запроса: «$gr_query="SELECT groups.ID, groups.number, groups.spec FROM `faculty` , `speciality` , `groups` WHERE speciality.faculty = faculty.ID AND groups.spec = speciality.ID AND faculty.ID = ' ".$faculty." ' ";») 12. Создать переменную grOptions для хранения HTML-разметки элементов options элемента select с идентификатором gr (раскрывающийся список групп). Сформировать элементы списка (по аналогии с пп. 9–10) в формате: значение – код группы (поле ID), отображаемый текст – специальность (поле spec)-номер группы (поле number). 13. Создать переменную response для представления полученных переменных specOptions и grOptions в формате XML с корневым элементом response и элементами options для хранения значений переменных specOptions и grOptions: $response = '<?xml version="1.0" encoding="windows-1251" standalone="yes"?>'. '<response>'. '<options>'. $specOptions. '</options>'. '<options>'. $grOptions. '</options>'. '</response>'; 14. Установить XML-формат передаваемых сценарием данных: header('Content-Type: text/xml'); 15. Вывести значение переменной $response; echo $response; 16. Ввести закрывающий тег PHP-сценария ?> 17. В текстовом редакторе (например, в «Блокноте») создать новый файл и сохранить его под именем GetGr.php. 18. Открыть тег PHP-сценария (см. п. 4). 19. Установить соединение с базой данных University (см. п. 5). 20. Создать переменную spec и записать в нее значения параметра spec, переданного со страницы Index.php: $spec = $_GET['spec']; 21. Создать запрос на извлечение данных о группах заданной специальности (текст запроса: «$gr_query="SELECT groups.ID, groups.number, groups.spec FROM `speciality` , `groups` WHERE groups.spec = speciality.ID AND speciality.ID = '".$spec." ' ";») (см. пп. 7–8). 22. Создать переменную grOptions для хранения HTML-разметки элементов options элемента select с идентификатором gr (раскрывающийся список групп). Сформировать элементы списка (по аналогии с пп. 9–10) в формате: значение – код группы (поле ID), отображаемый текст – специальность (поле spec)-номер группы (поле number) (см. пп. 9– 10). 23. Создать переменную response для представления полученных переменной grOptions в формате XML с корневым элементом response и элементом options для хранения значения переменной grOptions (см. п. 13). 24. Установить XML-формат передаваемых сценарием данных: header('Content-Type: text/xml'); 25. Вывести значение переменной response; echo $response; 26. Ввести закрывающий тег PHP-сценария ?> 27. В текстовом редакторе (например, в «Блокноте») создать новый файл и сохранить его под именем Ajax.js. 28. Создать переменную request для хранения экземпляра объекта XmlHttpRequest и присвоить ей значение null: var request = null; 29. Создать функцию для инициализации экземпляра объекта XmlHttpRequest 29.1. Ввести имя функции (createRequest) и открывающую фигурную скобку: function createRequest() { 29.2 Ввести программный код для попытки создания объекта XmlHttpRequest try { request = new XMLHttpRequest(); } 29.3 Ввести программный код для попытки создания объекта XmlHttpRequest в браузерах Microsoft (например, в Internet Explorer): catch (trymicrosoft) { { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } 29.4 Ввести программный код для попытки создания объекта XmlHttpRequest в браузерах, отличных от Microsoft: catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } 29.5 В случае невозможности создания объекта XmlHttpRequest присвоить переменной request значение null: catch (failed) { request = null; } } } 29.6 Если значение переменной request равно null, то вывести сообщение о невозможности создания объекта XmlHttpRequest if (request == null) alert("Ошибка при создании объекта XMLHttpRequest!"); 29.6 Ввести закрывающую фигурную скобку функции } 30. Создать функцию selectedFac, которая должна запускаться при выбора значения из списка факультетов. 30.1 Ввести имя функции (selectedFac) и открывающую фигурную скобку: function selectedFac() { 30.2 Извлечь значение выбранного из списка факультета и поместить это значение в переменную fac: var fac = document.getElementById("faculty").value; 30.3 Создать переменную для формирования URL-адреса серверного PHP-сценария (getSpecGr.php), к которому будет обращаться объект XMLHttpRequest. Сформировать GETзапрос для передачи сценарию параметра faculty со значением переменной fac: url = "getSpecGr.php?faculty=" + fac; 30.3 C помощью функции createRequest() создать объект XmlHttpRequest: createRequest(); 30.4 Инициализировать асинхронное подключение методом GET: request.open("GET", url, true); 30.5 Задать функцию обратного вызова (makeListSpecGr). Для этого с помощью свойства onreadystatechange указать браузеру, что при изменении состояния готовности запроса, браузер должен вызывать функцию JavaScript, назначенную в объекте запроса: request.onreadystatechange = makeListSpecGr; 30.6 Указать, что запрос не содержит данных (параметр запроса передается через URL): request.send(null); 30.7 Ввести закрывающую фигурную скобку функции } 31. Создать функцию makeListSpecGr 31.1 Ввести имя функции (makeListSpecGr) и открывающую фигурную скобку: function makeListSpecGr() { 31.2 Создать переменную spec и занести в нее объект с идентификатором spec (раскрывающийся список специальностей): var spec = document.getElementById("spec"); 31.3 Создать переменную gr и занести в нее объект с идентификатором gr (раскрывающийся список групп): var gr = document.getElementById("gr"); 31.4 Проверить состояние готовности запроса. Все операции должны выполняться только в том случае, если сервер завершил обработку запроса и все данные доступны в свойствах responseText или responseXML объекта запроса: if (request.readyState == 4) { 31.5 Проверить статус запрос. Все операции должны выполняться только в том случае, если программа успешно обработала запрос: if (request.status == 200) { 31.6 Создать переменную responseXML и занести в нее XML-результат работы серверного сценария: responseXml = request.responseXML; 31.7 Создать переменную xmlDoc и занести в нее корневой элемент XML-результата (элемент response), полученного от сервера: xmlDoc = responseXml.documentElement; 31.8 Создать переменную options_spec и занести в нее первый дочерний элемент корня XML-результата с именем options: options_spec = xmlDoc.getElementsByTagName("options")[0]; 31.9 Удалить все элементы раскрывающегося списка специальностей: while(spec.options.length) { spec.remove(0); } 31.10 Аналогичным образом удалить все элементы раскрывающегося списка групп. 31.11 Заполнить раскрывающийся список специальностей 31.11.1 Построить цикл по XML-элементам option элемента options со списком специальностей. Для этого ввести инструкцию for и открывающую фигурную скобку цикла: for(var i=0; i<options_spec.getElementsByTagName("option").length; i++) { 31.11.2 Создать новый элемент option: var option = document.createElement('option'); 31.11.3 Создать переменную text с текстовым содержимым текущего на итерации цикла элемента option: var text = options_spec.getElementsByTagName("option")[i].text; 31.11.4 Создать переменную value и занести в нее значение атрибута value текущего на итерации цикла элемента option: var value = options_spec.getElementsByTagName("option")[i].getAttribute("value") ; 31.11.5 Добавить в созданный в п. 31.11.2 элемент option атрибут value со значением из переменной value: option.setAttribute('value',value); 31.11.6 Добавить в созданный в п. 31.11.2 элемент option текстовый узел со значением из переменной text: option.appendChild(document.createTextNode(text)); 31.11.7 Добавить созданный в п. 31.11.2 элемент option к элементу spec (списку специальностей): spec.appendChild(option); 31.12 Аналогичным образом (см. п. 31.8) сформировать переменную options_gr для представления второго элемента options из XML-ответа сервера. 31.13. Заполнить раскрывающийся список групп (см. п. 31.11) 31.14 Ввести закрывающую угловую скобку проверки статуса запроса: } 31.15 Ввести инструкцию «иначе», выполняющуюся в том случае, когда запрос к серверу был выполнен неудачно: else { alert("Не удалось получить данные от сервера"); } 31.16 Ввести закрывающую угловую скобку проверки состояния готовности запроса: } 31.17 Ввести закрывающую фигурную скобку функции } 32. Создать функцию selSpec, которая должна запускаться при выбора значения из списка факультетов. (см. п. 30). Использовать следующий URL: url = "getListGr.php?spec=" + trim(spec);. В качестве функции обратного вызова использовать JavaScript-функцию makeListGr. 33. Создать функцию makeListGr (см. п. 31), формирующую список групп из XMLответа серверного сценария getListGr.php. 34. Открыть файл Index.php в текстовом редакторе (например, Блокноте или Notepad2) или HTML-редакторе. 35. Ввести в Index.php ссылку на JavaScript-сценарий Ajax.js. Для этого между открывающим и закрывающим тегами элемента HEAD ввести следующий код: <script type="text/javascript" src="Ajax.js"></script> 36. Добавить в раскрывающийся список факультетов (элемент select с именем faculty) вызов функции selectedFac при изменении выбранного значения списка. Для этого изменить открывающий тег элемента select следующим образом: <select name="faculty" style="width: 350px" onChange="selectedFac()"> 37. Аналогичным образом задать вызов функции selSpec при выборе специальности из раскрывающегося списка специальностей (элемент select с именем spec). 38. Протестировать полученное Web-приложение (см. лабораторную работу 1). Вариант В. Технология JSP и СУБД MySQL 1. Запустить визуальную среду Eclipse Europe Пуск | Программы | Eclipse 2. Создать новый проект File → New → Web → Dynamic Web Project 3. Присвоить проекту имя Lab3_JSP name → Lab3_JSP 4. Настроить Web-сервер для нового Web-приложения Вкладка Servers → кл. пр. кн. мыши | выбр. New → Server → ф. New Server | выбр. Apache Tomcat Server → кн. Finish 5. Добавить в проект новую JSP-страницу ф. Project Explorer | Lab1_JSP | кл. пр. кн. мыши → выбр. New → JSP | ф. New JavaServer Page | File name ← Default | удалить весь код элемента HTML 6. Скопировать в полученный файл весь код из файла Index.jsp из первой лабораторной работы. 7. Скопировать таблицу стилей style.css из предыдущей лабораторной работы и поместить ее в папку images, размещенную в каталоге с веб-приложением. 8. В любом редакторе (например, в «Блокноте») или в самой среде Eclipse создать новый файл и сохранить его под именем Ajax.js. 9. Создать переменную request для хранения экземпляра объекта XmlHttpRequest и присвоить ей значение null: var request = null; 10. Создать функцию для инициализации экземпляра объекта XmlHttpRequest 10.1. Ввести имя функции (createRequest) и открывающую фигурную скобку: function createRequest() { 10.2 Ввести программный код для попытки создания объекта XmlHttpRequest try { request = new XMLHttpRequest(); } 10.3 Ввести программный код для попытки создания объекта XmlHttpRequest в браузерах Microsoft (например, в Internet Explorer): catch (trymicrosoft) { { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } 10.4 Ввести программный код для попытки создания объекта XmlHttpRequest в браузерах, отличных от Microsoft: catch (othermicrosoft) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } 10.5 В случае невозможности создания объекта XmlHttpRequest присвоить переменной request значение null: catch (failed) { request = null; } } } 10.6 Если значение переменной request равно null, то вывести сообщение о невозможности создания объекта XmlHttpRequest if (request == null) alert("Ошибка при создании объекта XMLHttpRequest!"); 10.7 Ввести закрывающую фигурную скобку функции } 11. Создать функцию selectedFac, которая должна запускаться при выбора значения из списка факультетов. 11.1 Ввести имя функции (selectedFac) и открывающую фигурную скобку: function selectedFac() { 11.2 Извлечь значение выбранного из списка факультета и поместить это значение в переменную fac: var fac = document.getElementById("faculty").value; 11.3 Создать переменную для формирования URL-адреса серверного PHP-сценария (getSpecGr.php), к которому будет обращаться объект XMLHttpRequest. Сформировать GETзапрос для передачи сценарию параметра faculty со значением переменной fac: url = "getSpecGr.jsp?faculty=" + fac; 11.3 C помощью функции createRequest() создать объект XmlHttpRequest: createRequest(); 11.4 Инициализировать синхронное подключение методом GET: request.open("GET", url, true); 11.5 Задать функцию обратного вызова (makeListSpecGr). Для этого с помощью свойства onreadystatechange указать браузеру, что при изменении состояния готовности запроса, браузер должен вызывать функцию JavaScript, назначенную в объекте запроса: request.onreadystatechange = makeListSpecGr; 11.6 Указать, что запрос не содержит данных (параметр запроса передается через URL): request.send(null); 11.7 Ввести закрывающую фигурную скобку функции } 12. Создать функцию makeListSpecGr 12.1 Ввести имя функции (makeListSpecGr) и открывающую фигурную скобку: function makeListSpecGr() { 12.2 Создать переменную spec и занести в нее объект с идентификатором spec (раскрывающийся список специальностей): var spec = document.getElementById("spec"); 12.3 Создать переменную gr и занести в нее объект с идентификатором gr (раскрывающийся список групп): var gr = document.getElementById("gr"); 12.4 Проверить состояние готовности запроса. Все операции должны выполняться только в том случае, если сервер завершил обработку запроса и все данные доступны в свойствах responseText или responseXML объекта запроса: if (request.readyState == 4) { 12.5 Проверить статус запрос. Все операции должны выполняться только в том случае, если программа успешно обработала запрос: if (request.status == 200) { 12.6 Создать переменную responseXML и занести в нее XML-результат работы серверного сценария: responseXml = request.responseXML; 12.7 Создать переменную xmlDoc и занести в нее корневой элемент XML-результата (элемент response), полученного от сервера: xmlDoc = responseXml.documentElement; 12.8 Создать переменную options_spec и занести в нее первый дочерний элемент корня XMLрезультата с именем options: options_spec = xmlDoc.getElementsByTagName("options")[0]; 12.9 Удалить все элементы раскрывающегося списка специальностей: while(spec.options.length) { spec.remove(0); } 12.10 Аналогичным образом удалить все элементы раскрывающегося списка групп. 12.11 Заполнить раскрывающийся список специальностей 12.11.1 Построить цикл по XML-элементам option элемента options со списком специальностей. Для этого ввести инструкцию for и открывающую фигурную скобку цикла: for(var i=0; i<options_spec.getElementsByTagName("option").length; i++) { 12.11.2 Создать новый элемент option: var option = document.createElement('option'); 12.11.3 Создать переменную text с текстовым содержимым текущего на итерации цикла элемента option: var text = options_spec.getElementsByTagName("option")[i].text; 12.11.4 Создать переменную value и занести в нее значение атрибута value текущего на итерации цикла элемента option: var value = options_spec.getElementsByTagName("option")[i].getAttribute("value") ; 12.11.5 Добавить в созданный в п. 12.11.2 элемент option атрибут value со значением из переменной value: option.setAttribute('value',value); 12.11.6 Добавить в созданный в п. 12.11.2 элемент option текстовый узел со значением из переменной text: option.appendChild(document.createTextNode(text)); 12.11.7 Добавить созданный в п. 12.11.2 элемент option к элементу spec (списку специальностей): spec.appendChild(option); 12.12 Аналогичным образом (см. п. 12.8) сформировать переменную options_gr для представления второго элемента options из XML-ответа сервера. 12.13. Заполнить раскрывающийся список групп (см. п. 12.11) 12.14 Ввести закрывающую угловую скобку проверки статуса запроса: } 12.15 Ввести инструкцию «иначе», выполняющуюся в том случае, когда запрос к серверу был выполнен неудачно: else { alert("Не удалось получить данные от сервера"); } } } 13. Создать функцию selSpec, которая должна запускаться при выбора значения из списка факультетов. (см. п. 11). Использовать следующий URL: url = "getListGr.jsp?spec=" + spec;. В качестве функции обратного вызова использовать JavaScript-функцию makeListGr. 14. Создать функцию makeListGr (см. п. 12), формирующую список групп из XML-ответа серверного сценария getListGr.jsp. 15. Открыть файл Index.jsp. 16. Ввести в Index.jsp ссылку на JavaScript-сценарий Ajax.js. Для этого между открывающим и закрывающим тегами элемента HEAD ввести следующий код: <script type="text/javascript" src="Ajax.js"></script> 17. Добавить в раскрывающийся список факультетов (элемент select с именем faculty) вызов функции selectedFac при изменении выбранного значения списка. Для этого изменить открывающий тег элемента select следующим образом: <select name="faculty" style="width: 350px" onChange="selectedFac()"> 18. Аналогичным образом задать вызов функции selSpec при выборе специальности из раскрывающегося списка специальностей (элемент select с именем spec). 19. Скопировать в папку с веб-приложением файл Browse.jsp из первой лабораторной работы. 19. Проверить работоспособность созданного Web-приложения. Для этого в окне визуальной среды Eclipse выбрать пункт меню Project → Run as… → Run on Server 5. Контрольные вопросы 1. Каковы недостатки традиционного веб-программирования? 2. Каковы отличительные особенности технологии AJAX? 3. Что представляет собой объект XMLHttpRequest? 4. Что такое функция обратного вызова? 5. Чем отличается статус запроса от состояния запроса? 6. Содержание и оформление отчета Отчет должен содержать: – титульный лист, название и цель работы; – вариант задания; – листинг программного кода; – скриншоты результатов работы Web-приложения с различными вариантами запросов; – выводы по работе.