Безопасность — очень важный фактор для любого коммерческого web-сайта. Чтобы гарантировать безопасность, нужно придерживаться определенных принципов. Следует определить все риски и разработать план снижения этих рисков. Постоянный учет разработанных принципов позволяет обеспечивать безопасность даже в быстроменяющихся условиях. Следует обратить внимание, в частности, на следующие факторы:
конфиденциальность информации (information confidentially) — защита передаваемой или хранящейся на сайте информации;
аутентификация (authentication) — проверка регистрационной информации пользователя;
авторизация (authorization) — ограничение прав клиента при взаимодействии с системой;
целостность данных (data integrity) — гарантия того, что принятые по сети данные не изменены при пересылке случайно или преднамеренно;
отсутствие сбоев (non-repudiation) — обеспечение защищенности источника данных и целостности данных,
доступность (availability) — гарантия того, что система доступна всегда, когда это требуется.
Подробное изучение всех этих факторов выходит за рамки нашей книги, но существуют некоторые специфические вопросы, связанные с обработкой кредитных карт, которые мы рассмотрим в этой главе. При работе с персональной информацией клиента и особенно с номером его кредитной карты безопасность является предельно важным фактором.
Первой линией защиты является шифрование важной информации, которая пересылается между браузером пользователя и сервером электронного магазина. Обычно для этого используется протокол HTTPS (Secure Hypertext Transfer Protocol — безопасный протокол передачи гипертекста), в котором все данные, пересылаемые между браузером и сервером, шифруются с помощью технологии SSL (Secure Sockets Layer — слой защищенных сокетов). Если данные не зашифрованы, злоумышленники могут с легкостью прочесть информацию, которая пересылается между браузером и сервером.
Далее, все источники данных, в которых хранится важная информация, также должны быть зашифрованы. Если номера кредитных карт хранятся в базе данных, то эта база данных должна быть зашифрована во избежание несанкционированного доступа. Если данные хранятся в файле XML, то номера кредитных карт или сам файл должен быть зашифрован. Кроме того, данные должны храниться на компьютере, к которому невозможен доступ через Интернет.
На всех компьютерах следует использовать брандмауэры. Правильно сконфигурированные средства защиты могут значительно снизить риск несанкционированного доступа к информации. Отсутствие брандмауэра позволяет злоумышленникам осуществить все виды нападений на ваш сайт, так что эти средства защиты необходимы для любого коммерческого web-сайта.
Тщательно протестируйте вашу систему. Ошибки в системе часто оказываются теми лазейками, из-за которых не срабатывают средства защиты. Этого не произойдет, если система работает без сбоев. Поэтому тестирование системы имеет очень важное значение. Установка средств защиты зависит от программного обеспечения, используемого при реализации системы. Для установки протокола HTTPS необходимо, чтобы web-сервер был правильно сконфигурирован. Для шифрования базы данных также необходимо, чтобы она была правильно сконфигурирована. Мы не будем углубляться в детали установки средств обеспечения безопасности, так как они весьма разнообразны, но важность этого фактора трудно переоценить.
Если клиент не испытывает доверия к web-сайту, у него не возникнет желания передавать информацию, связанную с его кредитной картой. Между чтением информации на страницах электронного магазина и решением фактически приобрести товар — огромная разница. Можно посоветовать несколько способов повышения доверия клиента к web-сайту.
Качество работы сайта влияет на впечатления клиента от вашего электронного магазина. Если клиент сталкивается с неработающими ссылками или другими очевидными системными ошибками, вряд ли он будет относиться к такому сайту с доверием. Когда речь идет только о поиске информации, то подобные ошибки могут восприниматься достаточно легко, но когда дело доходит до сообщения важной персональной информации, надежная работа сайта становится критически важной.
Доступное изложение принципов работы с персональной информацией также очень важно для формирования доверительного отношения клиента. Если клиент не имеет представления о том, что произойдет с той информацией, которую он должен переслать на ваш сайт, он вряд ли захочет это сделать. Поэтому на сайте следует отвести специальную страницу, где четко объясняется, зачем нужна эта информация и как она будет обрабатываться; кроме того, необходимо, чтобы имелась четко обозначенная ссылка на эту страницу.
Неплохой идеей является предоставление клиенту возможности ознакомиться с теми мерами, которые предприняты для обеспечения безопасности при пересылке информации. Если вы объясните, что вся персональная информация зашифровывается перед отправлением и хранится в безопасном месте, клиент будет больше доверять вашему сайту.
Также на отношение клиента влияет общее впечатление от вашего сайта. Чем лучше выглядит ваш сайт, тем больше доверия он вызовет у посетителя. Оформление сайта, удобство навигации и другие факторы, влияющие на впечатление клиента, также будут влиять и на степень его доверия к сайту. Грамматические ошибки в тексте, неряшливое оформление и неудобство навигации неизбежно оттолкнут потенциальных покупателей.
Оплата и подтверждение заказа
В предыдущей главе мы показали, как в виртуальном магазине реализуется корзина покупателя. Теперь нам необходимо предоставить покупателю возможность фактически приобрести выбранные товары. Эта как раз та область, где посетители электронных магазинов проявляют наибольшее беспокойство, так что наша задача — гарантировать, чтобы этот процесс проходил гладко. Многие продажи в Интернете тормозятся на этом этапе взаимодействия с пользователем, в основном из-за нежелания пользователя передавать через Интернет информацию, связанную с его кредитной картой.
Эта страница вызывается из сервлета SubmitOrder, когда заказ получает подтверждение поставщика услуг по обработке. Эта простая страница включает в себя идентификатор заказа (листинг 5.26); ее можно использовать как квитанцию и при необходимости распечатать данные заказа. Так как у нас имеется объект Order с полной информацией о заказе, в страницу Approved можно включить помимо идентификатора и другие характеристики заказа.
Первое, что мы делаем в JSP-странице Confirmlnfo, — это помещаем информацию, введенную в форму на JSP-странице Creditlnfo, в объект Creditlnfo. При этом используются элементы jsp:useBean и jsp:setProperty, как и в двух предыдущих JSP-страницах. После того как получен объект Order, скриптлет извлекает из него объект Customer-Information, а затем вызывается метод setCreditlnfo, чтобы записать полученные значения, как показано в листинге 5.22.
Объект Shippinglnfo, связанный с определенным сеансом, создается в JSP-странице Creditlnfo. Информация о доставке, которая была введена в форму в JSP- странице Shippinglnfo, используется в JSP-странице Creditlnfo. Выбранный способ доставки заносится в параметр с именем shipperAndClass, а затем элемент jsp:setProperty вызывает метод setShipperAndClass объекта Shippinglnfo со значением этого параметра. Как уже говорилось ранее, при этом задается сразу и почтовая фирма, и вид доставки, то есть поля shipper и shippingClass (листинг 5.19).
JSP-страница Declined формируется, если по какой-либо причине кредитная карта клиента не прошла проверку поставщика. Страница генерирует сообщение, в котором указывается эта причина.
Простая JSP-страница OrderDateSelector (листинг 5.28) отображает форму с единственным полем ввода. В этом поле по умолчанию указана текущая дата, но пользователь (в данном случае работник отдела доставки) может ввести другую дату. Эта JSP-страница является точкой входа в процесс обновления информации о доставке.
JSP-страница SelectOredr (листинг 5.29) использует заранее определенную (стандартную) переменную request, чтобы получить введенную пользователем в JSP- страницу OredrDateSel ector дату. Эта дата требуется впоследствии для создания имени папки. Так как имя файла XML, содержащего сведения о заказе, включает в себя идентификатор данного заказа, все, что нужно сделать для отображения заказов, — это выделить идентификатор заказа из имени файла. Используя этот идентификатор, мы для каждого заказа создаем элемент HTML а для ссылки на JSP-страницу. Каждая ссылка содержит имя выбранного файла XML и папки, в которой этот файл содержится. Пользователь может просто щелкнуть на этой ссылке и увидеть соответствующий заказ. Например, если заказ с идентификатором 1014 был сделан 16 октября 2000 года, то ссылка будет иметь вид:
<а href="ShowOrder.jsp?dir= Orders_2000-10-16&file=0rder_1014.xml">1014</a>
После импорта необходимых классов для получения нового объекта класса Custo- merlnfo, связанного с текущим сеансом, используется элемент jsp:useBean. Затем свойства этого элемента с помощью элемента jsp:setProperty устанавливаются равными значениям, введенным в форму на странице Customerlnfo.html. После этого мы получаем класс Order, связанный с текущим сеансом, и вектор Vector, в котором содержится перечень всех заказанных товаров. Потом с помощью скриптлета [Скриптлетом (scriptlet) авторы называют код JSP внутри тегов <%...%>, по-видимому, по аналогии с апплетом и сервлетом (еще одним «изобретением» автора). — Примеч. ред. ] JSP вызываются методы setCustomerlnfo и setltems, которые добавляют соответствующие объекты в объект Order, как показано в листинге 5.17.
Эта страница отображает данные о заказе, который был выбран пользователем для просмотра. Для создания объектной модели документа задействуются выбранные с помощью описанной выше страницы файл и папка. Используя скрипт- леты (код внутри тегов <%..%>), мы производим анализ файла с помощью стандартных методов DOM. Результат этого разбора записывается в JSP-выражения (код внутри тегов <*=!...*>). Страница ShowOrder представлена в листинге 5.30. Хотя ее код довольно длинный, многие кодовые фрагменты повторяются.
Последняя JSP-страница, которую мы исследуем в этой главе, отвечает за обновление значений номера отслеживания и даты отправления, введенных на странице ShowOrder. На этой JSP-странице мы применим другой способ обработки файла XML. Перед нами стоит довольно-таки простая задача: нужно обновить значения двух переменных в файле XML. Вместо того чтобы использовать DOM и проводить анализ документа, а затем снова записывать его в виде файла XML, мы применим более простой метод текстовой обработки. Элементам, которые нам нужны, — tracki ng_number и date_sent — при создании файла XML были присвоены специальные значения, NO_TRACKING_NUMBER и NO_DATE_SENT. Обновление файла XML в данном случае сводится к элементарному контекстному поиску этих строк и замене их на новые значения.
Сначала JSP-страница получает пересланные ей параметры, включая скрытые поля формы. Для считывания файла XML создается объект BufferReader, a объект FileWriter используется для вывода обновленного файла XML. Каждая прочитанная строка XML передается методу replace для выполнения необходимых замен. Этот метод replace аналогичен методу replace класса String, единственное отличие заключается в том, что он оперирует не символами (то есть объектами типа char), а строками.
Описанная техника обработки текста в простых случаях пригодна для обработки документов XML. Ее использование позволяет избежать дополнительных сложностей и расходов, связанных с анализом документа XML. Но эта техника не всегда хорошо работает, если требуется произвести какие-либо сложные замены. Работая с документом XML как с простым текстовым документом, вы создаете слишком чувствительный к внешним условиям код, который не будет работать при любых изменениях DTD или формата XML. Использование анализатора кода является наилучшим решением, если требуется достаточно серьезная обработка документа XML.
После того как в документ XML внесены необходимые изменения, эта JSP- страница посылает клиенту с помощью класса Emailег сообщение, подтверждающее выполнение его заказа. Также она информирует поставщика услуг по обработке, что оформление заказа закончено, поэтому можно снимать деньги со счета клиента и переводить их на счет магазина, как показано в листинге 5.32.
Класс Authorization (листинг 5.4) используется для хранения данных, которые возвратил поставщик услуг по обработке. В нем имеются три поля: во-первых, булева переменная, указывающая, было ли получено подтверждение указанных клиентом сведений о кредитной карте. Затем имеется поле, в котором указываются причины отказа (если подтверждение не получено), и, наконец, поле, содержащее код подтверждения (если оно получено). Для всех этих полей имеются методы getXxx и setXxx, с помощью которых можно извлекать и модифицировать значения полей.
В классе Creditlnfo содержится информация о кредитной карте клиента. Сюда входит тип кредитной карты, например Visa или MasterCard, ее номер и дата истечения срока действия. Все эти сведения необходимо сообщить при обращении к поставщику услуг по обработке.
Класс Customerlnfo предназначен для сбора некоторой стандартной информации о покупателе. Имя покупателя и его адрес необходимы для того, чтобы ему можно было доставить заказ, а адрес электронной почты и номер телефона — для того, чтобы можно было связаться с клиентом и сообщить ему о каких-то изменениях или задать какие-либо вопросы. Объект Creditlnfo мы обсудим несколько позже. Класс Customerlnfo состоит только из методов getXxx и setXxx, как показано в листинге 5.1.
Класс Emailer используется для отправки электронных сообщений клиенту. Эти сообщения могут содержать подтверждение заказа или информацию о доставке. В этом классе имеются две статические переменные, необходимые для его конфигурирования. Первая переменная — имя сервера SMTP (Simple Mail Transfer Protocol — простой протокол электронной почты), который используется данным магазином для отправки почты. Вторая переменная — электронный адрес, который будет указан в письмах клиенту в качестве обратного, то есть в поле From (От). В нашем примере мы используем формат, в котором указывается как название фирмы XMLGifts, так и ее электронный адрес (orders® xmlgifts.com). Прежде чем использовать код, приведенный на прилагаемом к нашей книге компакт-диске, вы, разумеется, должны заменить эти данные теми, которые фактически фигурируют в вашей системе. Имя сервера SMTP, используемого для пересылки электронной почты, можно найти в параметрах конфигурации вашей почтовой программы. В листинге 5.12 показано начало кода класса Emailer.
В процесс выполнения заказа входит все, что должно быть сделано с товаром после оформления заказа. Обычно для этого нужно найти товар на складе, запаковать его и отправить клиенту. Мы рассмотрим несколько упрощенный вариант выполнения заказа; в нашем примере будет учитываться только сам процесс доставки.
В классе Fullfilment имеются поля для хранения информации о фирме, которая осуществляет доставку, и о типе услуг. Таким образом, мы можем доставлять товары с помощью различных почтовых фирм — например, Federal Express, UPS или почтовой службы US, а также выбирать различные типы услуг — срочную доставку на следующий день, через один или два дня или доставку в обычном режиме. Также нужно знать, сколько клиент должен заплатить за доставку. Эта сумма добавляется к стоимости товаров, что в результате дает полную стоимость заказа. Когда заказ наконец отправлен, ему должен быть присвоен некоторый идентификационный номер, а также следует записать дату отправки заказа — эти сведения потребуются, если от клиента поступят какие-либо вопросы, связанные с доставкой.
В классе Fullfilmerit (листинг 5.3) имеются методы setXxx и getXxx для каждого из полей. Имеется также один специальный метод, setShipperAndClass. Он позволяет задавать в одной строке и название почтовой фирмы, и тип услуг (для данного заказа) [Эту совокупность далее мы будем называть способом доставки. — Примеч. перев.]. Как вы увидите в разделе «JSP-страница Shippinglnfo», это упрощает обработку введенных пользователем данных (о предпочтительном способе доставки). В этом методе используется объект StringTokenizer, который разделяет строку на две части, затем первую часть заносит в поле shipper (почтовая фирма), а вторую — в поле class (тип услуг). Это сделано для того, чтобы упростить ввод указанных данных. Ниже мы рассмотрим страницу Shippinglnfo.jsp и увидим, как используется данный метод.
Класс Order служит в основном в качестве контейнера для всевозможных сведений, которые мы собираем при оформлении заказа. Сюда входит информация о клиенте, о доставке, номер кредитной карты клиента, перечень заказанных товаров и данные, присланные поставщиком услуг по обработке (в частности, код подтверждения). Нам также понадобится уникальный идентификатор этого заказа, чтобы на него можно было впоследствии ссылаться. Кроме того, нужно указать дату заказа. Все эти сведения вносятся в соответствующие поля класса Order. Конструктор класса задает идентификатор и дату заказа. Метод, используемый для генерации уникального идентификатора, мы исследуем несколько позже. В листинге 5.5 показаны методы getXxx и setXxx для полей класса. Для полей id и date методы setXxx отсутствуют, так как их значения задаются конструктором класса и затем не меняются.
Теперь нам нужен какой-нибудь способ подсчета стоимости доставки товара заказчику. Эта сумма зависит от нескольких факторов, главными из которых являются выбранная клиентом почтовая фирма и тип услуг. На стоимость также могут влиять вес посылки и расстояние до пункта назначения. Мы при вычислении общей стоимости будем учитывать только три фактора: почтовую фирму, тип услуг и вес посылки. Объекту ShippingCalculator в качестве параметра передается объект Order, в котором содержится вся необходимая информация о заказе: вес посылки и адрес пункта назначения.
Первый метод, getTypes, возвращает массив, в котором перечислены все типы услуг, предоставляемые каждой почтовой фирмой, сотрудничающей с магазином. Второй метод, getPrice, возвращает цену конкретного типа доставки конкретной фирмой. Входным параметром этого метода должна быть одна из строк массива, возвращенного методом getTypes.
Метод getPrice (листинг 5.11) можно расширить, чтобы учитывать при вычислении стоимости доставки большее количество факторов, чем перечисленные выше (вес посылки и способ доставки). Кроме того, было бы неплохо организовать считывание информации в этот класс из некоторого источника данных, например файла XML или базы данных, с последующим вычислением стоимости. Это позволило бы динамически менять указанные цифры в соответствии с реальными колебаниями цен, не меняя самого кода.
Следующие классы, которые мы будем рассматривать, используются в процессе оформления заказа. Первый из них занимается проверкой данных о кредитной
карте клиента. В этом примере мы создали очень простой класс, который возвращает код подтверждения в зависимости от последней цифры номера кредитной карты, содержащегося в классе Order. В настоящем электронном магазине вместо этого класса должен быть подставлен другой, который передает данные о кредитной карте поставщику услуг по обработке. Способ передачи этих данных в большой степени зависит от конкретного поставщика.
Класс TestPaymentAuthori zer представлен в листинге 5.10. Первый метод в этом классе, getAuthorization, в качестве параметра получает объект Order, из которого извлекается информация о кредитной карте для проверки. В нашем примере мы просто берем последнюю цифру номера и, если это 1, карта с таким номером отклоняется, то есть считается не прошедшей проверку. Этот абстрактный, произвольный критерий мы используем только для того, чтобы протестировать работу метода и продемонстрировать оба типа возвращаемых значений.
Метод capture нужен для того, чтобы завершить процесс снятия денег со счета клиента, осуществляемый поставщиком услуг по обработке. В нашем случае этот метод ничего не делает, но, опять-таки, в настоящем магазине он использовался бы для сообщения поставщику о том, что следует завершить процесс оплаты. Если бы мы хотели автоматизировать процесс возвращения денег в случае, когда клиент возвращает товар, или процесс разблокировки счета клиента, если заказанного товара не оказалось в наличии, то соответствующие методы следовало бы тоже поместить в класс TestPaymentAuthori zer.
В листинге 5.6 показаны некоторые методы, оперирующие данными, которые содержатся в классе Order. Первый метод, getTotalltemPrice, реализует цикл по всем заказанным товарам и для каждого товара умножает его цену на количество заказанных экземпляров. Затем подсчитывается и возвращается общая сумма. Метод getOrderTotal добавляет к общей сумме стоимость доставки, что и составляет общую стоимость заказа. Наконец, имеется метод getTotalltemWeight, который аналогичен методу getTotalltemPrice, но только в нем подсчитывается не стоимость, а общий вес заказа. Метод getPrice-осуществляет вспомогательные функции — удаляет дополнительные символы (знак $ и запятые) из строки с указанием цены, полученной из объекта Cartltem, а затем преобразует полученное число к типу doubl e.
Имеется также метод для записи заказа в формате XML. Информация о заказе может пригодиться в будущем. Поэтому мы создали определение DTD, которое является непосредственным отображением класса Order и всех классов, которые в нем используются. В листинге 5.7 представлен файл order.dtd, в котором каждому из полей класса Order (item, customer-Info, authorization и fullfilment) соответствует элемент, дочерний по отношению к элементу order. Поля id и date класса Order представлены атрибутами элемента order. Таким же образом сформированы и остальные элементы DTD: каждому полю класса Order соответствует элемент или атрибут в DTD [Order — заказ, item — товар, first name — имя, last name — фамилия, address — адрес, city — город, state — штат или страна, zip — почтовый индекс, phone — номер телефона, card number — номер кредитной карты, card type — тип кредитной карты, expiration date — дата окончания срока действия, reason — причина (отклонения кредитной карты), authorization code — код подтверждения, cost — стоимость, tracking number — номер для отслеживания заказа, date sent — дата отправки. — Примеч. перев. ].
В листинге 5.8 приведен метод, который создает документ XML, соответствующий этому определению DTD. Это примитивный, слишком прямолинейный метод, в котором просто перебираются все поля класса Order и для каждого поля выписываются элементы и атрибуты XML. Такой подход не всегда является оптимальным, так как изменения в классах, входящих в класс Order, приведут к необходимости изменения самого метода. Таким образом, теряются преимущества инкапсуляции, которую обеспечивает объектно-ориентированный подход к программированию. Было бы лучше рассматривать эти классы в единстве. Более удачный метод создания документа XML мы рассмотрим в главе 6.
Последний метод в классе Order, названный getllniqueld, приведен в листинге 5.9. Он генерирует уникальный идентификатор заказа. В нашем случае мы используем счетчик, который увеличивается на единицу каждый раз, когда нам требуется новый идентификатор. Этот счетчик должен храниться постоянно, чтобы мы могли быть уверенны в уникальности присваиваемых идентификаторов даже после полной перезагрузки системы. Хранение счетчика в памяти — в данном случае не выход из положения, так как при каждой перезагрузке системы счетчик начинает повторять уже присвоенные ранее идентификаторы. В качестве постоянного места хранения счетчика мы используем специальный файл.
Первый метод в этом классе используется для сообщения клиенту об отправке ему посылки с заказом. Хотя это подтверждение не является абсолютно необходимым, оно имеет большое значение, так как клиент, получив такое сообщение, будет уверен, что его заказ действительно выполняется, а также найдет ответы на возможные вопросы о доставке заказа. В этом методе после получения информации о пользователе из объекта класса Order мы вызываем служебный метод под названием <jetMessage, передавая ему в качестве параметра электронный адрес клиента. Метод getMessage создает объект Message с помощью интерфейса API JavaMail, о чем будет подробнее сказано далее в этом разделе. В объекте Message указывается тема сообщения и вносится текст, после чего письмо отправляется. Отправка письма осуществляется с помощью метода send объекта Transport из интерфейса API JavaMail. Этот метод создает простое сообщение (листинг 5.13), в котором указывается идентификатор заказа, чтобы клиент мог в дальнейшем на него ссылаться. Метод можно легко расширить, чтобы включить более детальную информацию о заказе.
Метод sendShipped (листинг 5.14) аналогичен методу sendConfirmation, отличие касается только текста посылаемого сообщения. /
Метод getMessage используется другими методами класса для осуществления большинства действий, необходимых при работе с интерфейсом API JavaMail. Аргументом этого метода является электронный адрес клиента, которому посылается сообщение. В первую очередь в этом методе создается новый объект Session, а его значением становится имя сервера SMTP, которое, как вы помните, берется из статической переменной класса Emailег. Затем создается новый объект Message и устанавливаются значения полей, отведенных для адресов отправителя и получателя сообщения, а также для текущей даты (на которую можно впоследствии ссылаться как на дату отправки сообщения).
Интерфейс прикладных программ (API) JavaMail — это набор классов, которые моделируют систему электронной почты и являются стандартным расширением Java. Этот интерфейс можно использовать для получения и отправления сообщений с помощью стандартных почтовых протоколов. Более подробную информацию вы найдете по адресу http://java.sun.com/products/javamail, и оттуда же вы сможете бесплатно загрузить версию 1.2 этого интерфейса API. Метод getMessage (листинг 5.15) использует интерфейс JavaMail для создания нового объекта Message, в котором указаны адреса отправителя и получателя, а также текущая дата.
Затем JSP-страница выдает код HTML, который позволяет пользователю выбрать один из предложенных способов доставки. В этом коде используется объект ShippingCalculator, рассмотренный нами выше в этой главе. Скриптлет, встроенный в код HTML, создает объект ShippingCalculator, а затем с помощью метода getTypes предлагает несколько способов доставки. На этом этапе создается ряд переключателей (radio buttons), по одному на каждый из указанных способов. Это делается с помощью цикла for. Для каждого способа создается элемент input типа radio. Атрибут value (значение) элемента устанавливается с помощью выражения JSP "<t=types[i]X>
". Затем такое же выражение используется для отображения этого значения на странице. Другой скриптлет обеспечивает получение данных о стоимости того или иного способа доставки с помощью метода getPrice объекта ShippingCalculator, как показано в листинге 5.18.
В этой JSP-странице сначала задается объект Fullfilment, связанный с данным сеансом и содержащийся в объекте Order. Также создается объект ShippingCalculator, который используется для подсчета выбранного способа доставки. После того как знак $ убран из строки с указанием цены, Shippinglnfo преобразуется к типу double и используется для вызова метода setCostToCustomer объекта Shippinglnfo (листинг 5.20).
Код HTML этой JSP-страницы используется для сбора необходимой информации о кредитной карте клиента. В первую очередь мы хотели бы отобразить в таблице полностью всю сумму, которую мы собираемся снять со счета клиента. Мы показываем общую стоимость покупки, стоимость доставки и суммарную стоимость заказа. Далее выводится форма, в которой клиент указывает тип своей кредитной карты, номер и дату окончания срока действия, как показано в листинге 5.21.
Код HTML этой страницы вновь отображает все введенные клиентом данные. Это позволяет клиенту проверить всю введенную им информацию до того, как она будет окончательно отправлена на сервер поставщика для получения подтверждения. Для этого берутся объекты Customerlnfo и Fullfilment, связанные с данным сеансом, и с помощью элементов jsp:getProperty из них извлекаются различные параметры заказа, которые затем отображаются на странице. Внизу страницы располагается кнопка, которая позволяет клиенту отправить данные на сервер, если он не обнаружил ошибок. Чтобы исправить неверно введенные данные, клиент может воспользоваться кнопкой Back (Назад) в окне браузера. Листинг 5.23 содержит код для отображения и проверки введенных клиентом данных.
Метод writeOrder используется для записи информации о заказе в файл XML. Этот метод помещает все файлы с заказами, поступившими в течение одного дня, в отдельную папку. Поэтому для определения даты (год, месяц и число месяца) создается специальный объект, GregorianCalendar. В имени папки указывается соответствующая дата, а название файла содержит идентификатор заказа. Метод mkdir класса File вызывается для проверки наличия данной папки, а затем с помощью метода writeXML объекта Order информация о заказе заносится в файл, как показано в листинге 5.25.
В нижней части этой JSP-страницы располагается форма, предназначенная для ввода номера отслеживания заказа и даты его отправки. Эти значения можно вводить в том случае, если в поле для номера указано значение NO_TRA- CKING_NUMBER (номер отсутствует). Эта строка используется для указания, что данное поле еще не инициализировано, так что пользователь может ввести новое значение. Если же значения уже заданы, они просто отобразятся и пользователь уже не сможет их редактировать. В этой форме (листинг 5.31) также имеется некоторое количество скрытых полей, которые содержат информацию, необходимую для JSP-страницы, обновляющей файл XML.
Листинги программ, приведенные в этой главе, показывают, как можно реализовать необходимые для работы магазина функции по обработке заказов и составлению счетов. Чтобы использовать эти программы в реальном магазине, необходима некоторая доработка. Наибольшие изменения будут касаться требований безопасности. JSP-страницы, которые задействуются в процессе ввода информации клиентом, должны использовать не простой протокол HTTP, a HTTPS. Далее, в нашем примере информация о клиентах хранилась в незашифрованном файле в той же системе файлов, в которой работает web-сервер магазина. В идеале вся персональная информация о клиентах должна храниться в зашифрованном, безопасном источнике данных на изолированном сервере, к которому нет доступа из Интернета.
С другой стороны, необходимо заменить класс, отвечающий за проверку номеров кредитных карт, на класс, который будет взаимодействовать с реальным поставщиком услуг по обработке. Но в процессе тестирования системы, на том этапе, когда еще не нужно взаимодействие с реальным поставщиком, можно воспользоваться приведенным здесь классом.
После того как клиент ввел и подтвердил информацию о заказе, отдел доставки электронного магазина должен иметь возможность просматривать эту информацию и обновлять значения таких характеристик, как номер заказа и дата отправки заказа клиенту. Мы также предложим способ формирования списка всех заказов, поступивших в конкретный день, и выбора из этого списка определенного заказа.
Для коммерческих web-сайтов, занимающихся розничной продажей, прием платежей через кредитные карты является общепринятой практикой. Вообще говоря, оплата по кредитной карте товаров, приобретенных как непосредственно в магазине, так и через систему «товары почтой», появилась на много лет раньше, .чем WWW. На розничном уровне электронной торговли сложилась определенная последовательность действий, необходимая для оплаты через кредитные карты, и каждый электронный магазин работает с кредитными картами на основе этой последовательности. Прежде чем исследовать подробности ее реализации, рассмотрим, из каких этапов она складывается.
В процессе оплаты товара кредитной картой участвует несколько действующих лиц: сам клиент, магазин, банк клиента, поставщик услуг по обработке и поставщик коммерческих услуг. Роли клиента и магазина в процессе оплаты товара более или менее ясны. Банк клиента — это финансовое учреждение, которое выдало ему кредитную карту. В следующих двух абзацах описываются роли двух остальных действующих лиц.
Поставщик коммерческих услуг магазина часто является банком, но может быть и другим финансовым институтом; например, в этом качестве может выступать сама компания, выпускающая кредитные карты. Чтобы работать с кредитными картами, магазин должен заключить с банком соглашение. Требования и условия у каждого банка свои, но, как правило, взимаются по крайней мере три вида платежей. Во-первых, имеется так называемая учетная ставка (discount rate), размер которой обычно колеблется от 2,5 до 5 %. Это процент, отчисляемый от каждого платежа, который проходит через коммерческого поставщика. Во-вторых, при прохождении каждого платежа отчисляется некоторая небольшая фиксированная сумма, обычно в пределах от 30 до 50 центов (transaction fee). Наконец, коммерческий банк обычно взимает за свои услуги некоторую ежемесячную оплату. Магазин и банк должны договориться обо всех этих платежах, прежде чем магазин начнет принимать к оплате кредитные карты.
Наконец, пятым действующим лицом в этом процессе является поставщик услуг по обработке. Другое название этого поставщика — расчетная палата (clearinghouse). В его обязанности входит прием запросов от магазина, проверка достоверности полученных от клиентов сведений, проверка наличия на счетах покупателей достаточных средств и, наконец, перевод денег между банками.
Фактически процесс оплаты кредитной картой состоит из двух этапов. Сначала магазин посылает поставщику услуг по обработке запрос о проверке сведений, поступивших от клиента. В этом запросе указываются сумма покупки, номер кредитной карты и адрес клиента. Поставщик проверяет существование указанного счета в банке, наличие на счету клиента достаточной суммы и, возможно, адрес владельца кредитной карты. Если все в порядке, то поставщик высылает магазину код подтверждения. На этом этапе не происходит никакой передачи денег, но на счету клиента блокируется сумма, равная сумме заказа, сделанного им в электронном магазине.
Следующий этап процесса обработки (этап, когда деньги фактически снимаются со счета клиента) начинается после того, как магазин закончил всю деятельность по выполнению заказа. Поставщику услуг по обработке посылается второе сообщение. В реальном магазине (в отличие от виртуального) этот этап начинается после того, как покупатель вышел из магазина со своей покупкой. Обычно в таком магазине все чеки после завершения рабочего дня (или смены) собираются и отсылаются вместе. Но чек, в принципе, может быть послан и отдельно. В электронном магазине снятие денег со счета клиента происходит не ранее чем ему фактически отправлен товар. Это предотвращает вероятность слишком раннего снятия денег со счета клиента, например в случае, если товар на складе временно отсутствует.
Помимо подтверждения правильности сведений о кредитной карте и фактического снятия денег со счета клиента поставщик услуг по обработке осуществляет и другие функции, например расторжение сделки. Например, если после завершения первого этапа оказывается, что по какой-либо причине заказ не может быть выполнен (например, товар отсутствует на складе или клиент раздумал его покупать), осуществляется расторжение сделки, то есть снимается блокировка с соответствующей суммы денег на счету клиента.
Еще один вид услуг, выполняемых этим поставщиком, — возвращение денег клиенту. Если клиент по какой-либо причине возвращает поставщику товар, оплаченный по кредитной карте, то деньги за возвращенный товар снова заносятся на счет клиента.
Для небольших web-магазинов, возможно, не имеет смысла пытаться полностью автоматизировать описанный процесс. Если количество заказов невелико, то может оказаться более экономичным выполнять все описанные действия «вручную». При этом проверка кредитных карт клиентов, вероятно, займет несколько более длительное время, но в целом такое решение может оказаться предпочтительным для небольших электронных магазинов, которые только начинают свою деятельность.
Существует множество компаний, предлагающих услуги по организации всего описанного процесса электронным магазинам, которые хотели бы автоматизировать обработку электронных платежей. Эти компании являются либо поставщиками услуг по обработке, либо посредниками между такими поставщиками и электронными магазинами. Возможности и условия этих компаний сильно различаются, так что перед тем, как сделать выбор, вам предстоит изучить множество предлагаемых вариантов. Можно порекомендовать такие компании, как CyberSource (www.cybersource.com), Verifone (www.venfone.com), Authonze.net (www.authonze.net) и Clear-Commerce (www.clearcommerce.com). Большая часть этих компаний предлагают не только услуги по обработке, но и установку соответствующего программного обеспечения на web-сайт поставщика коммерческих услуг, что упрощает взаимодействие с ним.
Когда покупатель отобрал товары, которые он собирается приобрести, следующим этапом является подсчет стоимости покупки и выполнение заказа. Необходимо получить определенную информацию о покупателе, в том числе его имя, адрес и номер телефона или адрес электронной почты (или установить какой- нибудь другой способ связи с ним). Также покупатель может выбрать один из способов доставки товара. Наконец, самое главное — покупатель должен сообщить номер своей кредитной карты, которой он будет оплачивать покупку.
Мы начнем с изучения классов, которые будут использоваться в JSP-страни- це как компоненты JavaBean. Customerlnfo, Creditlnfo, Fulfillment, Authorization и Order — все это классы, которые содержат информацию, собранную в процессе оформления заказа.
Следующие три класса, которые мы изучим, — TestPaymentAuthorizer, Ship- pi ngCal cul ator и Eraai 1 er — также используются в процессе оформления заказа. Затем мы рассмотрим HTML-страницу, сервлет и несколько JSP-страниц, с помощью которых осуществляется взаимодействие с пользователем при сборе необходимой информации.
Когда подтвержденные клиентом данные (то есть JSP-страница Confirmlnfo) отправлены, необходимо послать поставщику услуг по обработке сведения, связанные с оплатой заказа. Это делается с помощью сервлета SubmitOrder. Здесь мы используем не JSP-страницу, а сервлет, поскольку данная процедура, с одной стороны, требует довольно много кода, а с другой стороны, генерирует сравнительно немного выходных данных. Дело в том, что, как правило, создавать и отлаживать сервлеты проще, чем JSP-страницы, но отрицательной стороной сер- влетов является сложность генерируемого кода HTML.
Главная точка входа в сервлет — метод doGet, который получает объект Session, соответствующий текущему сеансу (листинг 5.24). Затем мы получаем объект Order, сформированный для этого сеанса предыдущими JSP-страницами. Далее для получения подтверждения данных кредитной карты используется класс TestPaymentAuthorizer. Если подтверждение получено, клиенту посылается соответствующее сообщение с помощью класса Emailег, вызывается метод, который записывает заказ в специальный файл, и вызывается JSP-страница Approved.jsp, создающая сообщение с информацией о подтверждении заказа и указанием идентификатора заказа. Если подтверждение не было получено, вызывается JSP-страница Declined .jsp и создается другое сообщение.
Теперь мы перейдем к классам, с помощью которых осуществляется получение всей информации от клиента и передача ее рассмотренным выше классам. В первую очередь — это HTML-страница Customerlnfo.html. На этой странице имеется форма, поля которой предназначены для введения информации пользователем и соответствуют полям класса Customerlnfo (листинг 5.16). Как будет видно на JSP-странице Shippinglnfo, это соответствие упрощает передачу данных из формы в класс.