В этой статье мы рассмотрим практическое приложение, созданное с
использованием WML и ASP. Мы разработаем "корзину" для магазина некой компании по
продаже бумаги для печатающих устройств. Предложенное приложение покажет
продавцу компании состояние склада, используя его WAP-телефон, и в то же
время позволит ему разместить заказ для клиента. Это приложение
иллюстрирует некоторые концепции в WML и то, как
WML и ASP могут использоваться вместе для создания динамических
WAP-приложений.
Проектирование БД
Компания поддерживает базу данных
Stock.mdb, содержащую следующие таблицы: Inventory (Опись), Orders (Заказы) и
Staff (Персонал). Отношения для таблиц следующие:
Таблица Inventory содержит
идентификатор (SKU) изделия и его запас, а также себестоимость и продажную цену.
Таблица Orders используется, чтобы фиксировать заказы, сделанные продавцом
компании. Таблица Staff содержит информацию входа в систему продавца.
Запуск приложения
Чтобы проверить примеры приложения, описываемые в этой статье, вы можете использовать UP.SDK 4.0 Beta 1 WAP Phone Emulator. UP.SDK доступен для загрузки на сайте Phone.com. Чтобы протестировать
приложение, используйте UP.SIMULATOR.
WAP Телефоны, поддерживающие UP.BROWSER
В настоящее время более 20
изготовителей лицензировали UP.BROWSER для своих мобильных телефонов. Среди них
Motorola, Ericsson, Nokia и Toshiba. Для получения полного списка мобильных
телефонов, поддерживающих UP.BROWSER, посетите
http://updev.phone.com/dev/ts/up/phones.html.
Переносимость приложения
Пример,
иллюстрированный здесь, был проверен только на UP.SIMULATOR. Поскольку
различные изготовители телефонов имеют слегка различное исполнение WML,
приложение, написанное в WML и проверенное на одной программе просмотра, может
не работать правильно в другой. Поэтому возможно, что при загрузке данных исходных текстов вам потребуется
адаптировать их к некоторым иным программам просмотра.
Вход в программу
Каждому продавцу от нашей гипотетической компании PaperClip
присваивается StaffID и пароль для доступа к информации склада. Код
для входа продавца:
<% Response.ContentType = "text/vnd.wap.wml" %>
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<!-- Welcome Screen -->
<card id="Welcome" title="Welcome">
<p>
Welcome to PaperClip WAP Services
<img alt="" localsrc="paperclip" src=""/>
<br/>
StaffID ? <input name="StaffID" type="text" maxlength="8" />
Password ? <input name="Password" type="password" maxlength="8" />
<do type="accept" label="Login">
<go href="Login.asp" method="post">
<postfield name="StaffID" value="$StaffID" />
<postfield name="Password" value="$Password" />
</go>
</do>
</p>
</card>
Первая
часть кода должна установить тип документа. Вы можете обратить внимание, что
вышеупомянутый код содержит только WML-разметку за исключением первой
строки:
<% Response.ContentType = "text/vnd.wap.wml" %>
Использование свойства ASP Response.ContentType гарантирует, что
тип MIME установлен правильно.
<% Response.ContentType = "text/vnd.wap.wml" %>
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
Обратите внимание на
изображение скрепки на экране входа в систему. Оно создано WML–тэгом
<img>.<img alt="" localsrc="paperclip"
src=""/>
Атрибут localsrc <img> элемента определяет список
изображений, доступных телефону локально. Для полного списка доступных
изображений, обратитесь к WML Language Reference, стр. 37. Большинство
элементов WML подобны HTML. Прежде, чем мы перейдем к следующему экрану,
рассмотрим этот код:
<do type="accept" label="Login">
<go href="Login.asp" method="post">
<postfield name="StaffID" value="$StaffID" />
<postfield name="Password" value="$Password" />
</go>
</do>
Элемент сопоставляет задачу с
клавишей интерфейса пользователя телефона. Для UP.SIMULATOR:
После того, как продавец
ввел свой StaffID и пароль, он нажимает на клавишу accept (Login), для
подтверждения подлинности его идентификации.
Идентификация
Как только продавец введет
StaffID и пароль, приложение перейдет к подтверждению его
подлинности.
<template>
<do type="options" label="Search">
<go href="Search.asp" />
</do>
</template>
<!-- Login Card -->
<card id="Login" title="Login">
<p>
<%
sqlQuery = "SELECT * FROM Staff WHERE StaffID='"
Request.Form("StaffID") & "' AND Password='"
Request.Form("Password") & "'"
set rs = conn.Execute(SQLquery)
if rs.EOF then
Response.Write "Invalid Login"
Response.Write "<do type='accept' label='Retry'>"
Response.Write " <go href='index.asp'/>"
Response.Write "</do>"
'---override the <template> element
Response.Write "<do type='options' label=''>"
Response.Write " <go href=''/>"
Response.Write "</do>"
else
Session("StaffID") = Request.Form("StaffID")
Session("Password") = Request.Form("Password")
Response.Write "<strong>Welcome, " & rs.Fields("Name") & "! </strong><br/>"
sqlQuery = "SELECT * FROM Inventory"
Set rs = conn.Execute(SQLquery)
%>
Если продавец не прошел
идентификацию, появляется экран, показанный здесь. Заметьте, что, когда
пользователь не сумел войти, элемент <template>:
<template>
<do type="options" label="Search">
<go href="Search.asp" />
</do>
</template>
заменяется на:
'---override the <template> element
Response.Write "<do type='options' label=''>"
Response.Write " <go href=''/>"
Response.Write "</do>"
Это гарантирует, что функция поиска недоступна
неидентифицированному пользователю. Как только пользователь прошел регистрацию,
его StaffID и пароль сохраняются в объекте session.
Относительно поддержки Cookies
В этом приложении был использован объект Session в ASP. Поскольку объект Session требует
поддержки cookies на стороне клиента, предположим, что платформа, которая
используется, чтобы выполнить это приложение, поддерживает cookies. В частности,
при разработке приложений, которые будут развернуты в реальном мире,
гарантируйте, что Ваш WAP шлюз использует поддержку cookies. UP.SIMULATOR
поддерживает cookies, и, таким образом, мы можем использовать их для
создания двух переменных сессии:
Session("StaffID") = Request.Form("StaffID")
Session("Password") = Request.Form("Password")
Эти две переменные сессии могут использоваться повсюду в
приложении для идентификации пользователя, который его запустит.
Если платформа не поддерживает cookies, то StaffID и пароль
должны передаваться от входной формы до их повторного использования при помощи
методов get или post (элементы <go> и <postfield >).
Получение списка описи
Как только пользователь
идентифицирован, сценарий ASP начнет генерировать список доступных изделий. Для
простоты изложения ограничим число предметов в списке десятью предметами.
<anchor>
View Cart
<go href="cart.asp" />
</anchor>
<br/>Stock List:
<select name="stockID">
<%
while not rs.EOF
%>
<option value="<% =rs("SKU") %>">
<% =rs("SKU") %>-<% =rs("Name") %>(<% =rs("OnHand") %>)
$$<% =rs("CostPrice") %> - $$<% =rs("SellPrice") %>
</option>
<%
rs.MoveNext
Wend
%>
</select>
<do type="accept" label="Order">
<go href="cart.asp" method="get">
<postfield name="SKU" value="$stockID" />
</go>
</do>
Мы будем использовать элемент
<anchor> для создания гиперсвязи просмотра содержания корзины покупок. Что
касается списка предметов, доступных в таблице описи, будем использовать элементы
<select> и <option>.
В этом примере информация о товаре
выводится в одну строку. На UP.SIMULATOR длинные строки переводятся на следующую
строку. Однако внимательный читатель может заметить, что различные WAP -
броузеры имеют различную обработку длинных строк и могут просто обрезать все
избыточные символы, которые не помещаются на той же самой строке. Поэтому с
самого начала рассмотрите платформу, на которой будет выполняться ваше
приложение.
Ввод для функций «Заказ» и «Поиск»
соответственно:
>do type="accept" label="Order"<
>go href="cart.asp" method="get"<
>postfield name="SKU" value="$stockID" /<
>/go<
>/do<
>template<
>do type="options" label="Search"<
>go href="Search.asp" /<
>/do<
>/template<
Обратите внимание, что здесь был
использован элемент < template >, чтобы отделить параметр «Поиск». Элемент
template определяет связи на уровне деки и относится ко всем платам в
деке. Если пользователь щелкает на клавише Up, «фокус» переходит на ссылку
View Cart. Формат отображенного товара - SKU-Название- (Количество
-Себестоимость-Цена Продажи).
Клавиша accept теперь изменена на
Link. Щелчок по клавише accept покажет содержимое корзины. Добавление товара а корзину Для добавления
товара в корзину просто выберем элемент и нажмем на клавишу accept.
При добавлении товара
отображается содержание корзины. Изображенный ниже код добавляет товар в
корзину:
sqlQuery = "INSERT INTO Orders (StaffID, SKU, Qty, OrderDate) "
sqlQuery = sqlQuery + "Values ('" & Session("StaffID") & "','" & "
sqlQuery = sqlQuery + "Request.QueryString("SKU") & "',1,'" & date & "')""
On Error Resume Next '---prevent duplicate items from crashing my program---
set rs = conn.Execute(sqlQuery)
rs.Close 'Displaying the Cart Content
Следующий код показывает содержание корзины:
'---Displays the cart content---
Response.Write "<br/><strong>Cart Contents</strong>"
sqlQuery = "SELECT * FROM Orders INNER JOIN Inventory ON
Orders.SKU=Inventory.SKU WHERE StaffID='" &
Session("StaffID") & "'"
set rs = conn.Execute(sqlQuery)
if not rs.EOF then
Response.Write "<select name='CartItem'>"
While not rs.EOF
Response.Write "<option value='" & rs("SKU") & "'>" & rs("SKU") & _
"-" & rs("Name") & "(" & rs("qty") & ")</option>"
rs.MoveNext
Wend
Response.Write "</select>"
rs.Close
%>
<do type="option" label="Qty">
<go href="EditCart.asp" method="get">
<postfield name="SKU" value="$CartItem" />
</go>
</do>
<%
else
%>
<br/>Cart is empty!
<do type="accept" label="Main">
<go href="login.asp" method="post">
<postfield name="StaffID" value="<% =Session("StaffID") %>" />
<postfield name="Password" value="<% =Session("Password") %>" />
</go>
</do>
<%
end if
%>
Заметьте, что, если тележка пуста, клавиша ACCEPT будет
отображена как Main и возвратит пользователя к основной экранной
странице.
В корзине две ссылки [Главная] и [Поиск], и два параметра: Delete и
Qty (чтобы изменить количество товара). Чтобы удалить товар,
щелкните на клавише ACCEPT (Delete).
<template>
<do type="accept" label="Delete">
<go href="Cart.asp" method="get">
<postfield name="delete" value="$CartItem" />
</go>
</do>
</template>
Чтобы изменить количество товар, щелкните на клавише option (Qty).
<do type="option" label="Qty">
<go href="EditCart.asp" method="get">
<postfield name="SKU" value="$CartItem" />
</go>
</do>
Изменение количества товара в корзине
Когда пользователь нажимает на клавишу option (Qty), исполняется файл EditCart.asp.
<card id="GetQty" title="Get Qty">
<p>
Qty? <input name="Qty" type="text" maxlength="3" />
<do type="accept" label="Set">
<go href="EditCart.asp" method="get">
<postfield name="SKU" value="<% =Request.QueryString("SKU")%>" />
<postfield name="qty" value="$Qty" />
</go>
</do>
</p>
</card>
Чтобы изменить
количество, введите число и нажмите на клавишу accept ( Set
). sqlQuery = "UPDATE Orders SET Qty=" &
Request.QueryString("qty") & _ " WHERE StaffID='" &
Session("StaffID") & "' AND SKU='" & _ Request.QueryString("SKU")
& "'" set rs = conn.Execute(sqlQuery) 'response.write
sqlquery '---display the content of the
cart--- Response.Redirect "cart.asp"
После изменения количества WAP – броузер перенаправит на cart.asp, где отобразится обновленное содержание
корзины.
Удаление товара из корзины
Для этого нажмите на кнопку accept (Delete).
'---check to see if this is a deletion?---
ItemToDelete = Request.QueryString("delete")
if ItemToDelete<>"" then
'---delete an item---
sqlQuery = "DELETE FROM Orders WHERE StaffID='" & Session("StaffID")"
sqlQuery = sqlQuery + " & "' AND SKU='" & ItemToDelete & "'""
set rs = conn.Execute(sqlQuery)
'rs.Close
Поиск товара
Поиск можно производить из основной страницы и со страницы корзины
Для поиска введите SKU товара и нажмите на кнопку accept (Locate).
sqlQuery = "SELECT * FROM Inventory WHERE SKU LIKE '%" & SearchStr & "%'"
Set rs = conn.Execute(SQLquery)
Выведем результаты поиска
Response.Write "<select name='stockID'>"
While not rs.EOF
Response.Write "<option value='" & rs("SKU") & "'>" & rs("SKU") & "-" _
& rs("Name") & "(" & rs("OnHand") & ") $$" & rs("CostPrice") & "-$$" _
& rs("SellPrice") & "</option>"
rs.MoveNext
Wend
Response.Write "</select>"
Со страницы поиска можно заказать товар или перейти на главную
страницу
Отладка WAP-программы
Немногие симуляторы позволяют удобно работать с отлаживаемым WAP-приложением. Однако, в UP.Simulator во все время работы открыто окно Phone Information Window.
Окно Phone Information представляет полезную информацию для WAP разработчика. В нем отображены все HTTP
запросы и WML страницы, которые вы загружаете с сервера. Наиболее полезная
особенность - способность показать неправильно созданную WML страницу. Пример
ниже:
<% Response.ContentType = "text/vnd.wap.wml" %>
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<!-- Welcome Screen -->
<card id="Welcome" title="Welcome">
<p>
Welcome to PaperClip WAP Services <img alt="" localsrc="paperclip" src=""/>
<br>
StaffID ? <input name="StaffID" type="text" maxlength="8" />
Password ? <input name="Password" type="password" maxlength="8" />
<do type="accept" label="Login">
<go href="Login.asp" method="post">
<postfield name="StaffID" value="$StaffID" />
<postfield name="Password" value="$Password" />
</go>
</do>
</p>
</card>
Обычная ошибка -
пропущено "/" после <br>. UP.Simulator отобразит такую картинку:
В окне Phone Information мы получим
======================= WML Errors =====================
WML translation failed.
(10) : error: Expected tag end(>) instead of <newline>
(10) : error: Expected </ instead of TEXT ''
(10) : error: Invalid element 'PCDATA' in content of 'br'. Expected closing tag
(10) : error: Invalid element 'input' in content of 'br'. Expected closing tag
(11) : error: Invalid element 'PCDATA' in content of 'br'. Expected closing tag
(11) : error: Invalid element 'input' in content of 'br'. Expected closing tag
(12) : error: Invalid element 'do' in content of 'br'. Expected closing tag
(18) : error: Close tag 'p' does not match start tag 'br'
(19) : error: Close tag 'card' does not match start tag 'p'
(29) : error: Close tag 'wml' does not match start tag 'card'
(29) : error: Expected the end of root element instead of end of file
======================= End Errors =====================
************************ Current WML ******************************************
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD
/wml_1.1.xml">
<wml>
<!-- Welcome Screen -->
<card id="Welcome" title="Welcome">
<p>
Welcome to PaperClip WAP Services <img alt="" localsrc="paperclip" src=""/
<br>
StaffID ? <input name="StaffID" type="text" maxlength="8" />
Password ? <input name="Password" type="password" maxlength="8" />
<do type="accept" label="Login">
<go href="Login.asp" method="post">
<postfield name="StaffID" value="$StaffID" />
<postfield name="Password" value="$Password" />
</go>
</do>
</p>
</card>
</wml>
********************************************************************************
Translation failed for content-type: text/vnd.wap.wml
----------------- DATA SIZE ------------------------
Uncompiled data from FILE is 266 bytes.
...found Content-Type: text/vnd.wap.wml.
Compiled WAP binary is 96 bytes.
----------------------------------------------------
В сообщении об ошибках мы можем видеть, что строка 10 содержит ошибку и что
ожидается "/". Мы можем также просмотреть коды WML, которые посланы
UP.SIMULATOR. Коды отображены в конце окна Phone Information. Еще одна
интересная информация – размер неоткомпилированных и откомпилированных WAP
данных.
----------------- DATA SIZE ------------------------
Uncompiled data from FILE is 266 bytes.
...found Content-Type: text/vnd.wap.wml.
Compiled WAP binary is 96 bytes.
----------------------------------------------------
Заключение
В этой статье Вы увидели, как
типичное приложение E-коммерции может быть адаптировано для WAP устройств.
Очевидно , что размер экрана накладывает серьезные ограничения на
разрабатываемые приложения. Однако есть и хорошие новости. Навыки
программирования HTML и ASP существенно помогают при создании приложений WAP.
Очевидно, в ближайшие месяцы компании будут писать две различные версии
приложений для Интернет: одну для Web, а другую для WAP. Другая проблема –
совместимость броузеров для WAP.Это напоминает создание страниц под Microsoft
Internet Explorer и Netscape Navigator.
|