WAP и ASP - Часть III

WAP и ASP - Часть III

Автор: Wei Meng Lee           

Источник: Relib.com             

 

В этой статье мы рассмотрим практическое приложение, созданное с использованием 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>

Элемент сопоставляет задачу с клавишей интерфейса пользователя телефона.

 

После того, как продавец ввел свой 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.