к библиотеке   к оглавлению   Банки данных Интернет   визуальные среды - 4GL   технологии программирования

Язык XML

Оплата и подтверждение заказа

В предыдущей лекции мы показали, как в виртуальном магазине реализуется корзина покупателя. Теперь нам необходимо предоставить покупателю возможность фактически приобрести выбранные товары. Эта как раз та область, где посетители электронных магазинов проявляют наибольшее беспокойство, так что наша задача — гарантировать, чтобы этот процесс проходил гладко. Многие продажи в Интернете тормозятся на этом этапе взаимодействия с пользователем, в основном из-за нежелания пользователя передавать через Интернет информацию, связанную с его кредитной картой.

Процесс оплаты

Для коммерческих 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-сайт поставщика коммерческих услуг, что упрощает взаимодействие с ним.

 

Безопасность

Безопасность — очень важный фактор для любого коммерческого web-сайта. Чтобы гарантировать безопасность, нужно придерживаться определенных принципов. Следует определить все риски и разработать план снижения этих рисков. Постоянный учет разработанных принципов позволяет обеспечивать безопасность даже в быстроменяющихся условиях. Следует обратить внимание, в частности, на следующие факторы:

Подробное изучение всех этих факторов выходит за рамки нашего курса, но существуют некоторые специфические вопросы, связанные с обработкой кредитных карт, которые мы рассмотрим в этой главе. При работе с персональной информацией клиента и особенно с номером его кредитной карты безопасность является предельно важным фактором.

Первой линией защиты является шифрование важной информации, которая пересылается между браузером пользователя и сервером электронного магазина. Обычно для этого используется протокол HTTPS (Secure Hypertext Transfer Protocol — безопасный протокол передачи гипертекста), в котором все данные, пересылаемые между браузером и сервером, шифруются с помощью технологии SSL (Secure Sockets Layer — слой защищенных сокетов). Если данные не зашифрованы, злоумышленники могут с легкостью прочесть информацию, которая пересылается между браузером и сервером.

Далее, все источники данных, в которых хранится важная информация, также должны быть зашифрованы. Если номера кредитных карт хранятся в базе данных, то эта база данных должна быть зашифрована во избежание несанкционированного доступа. Если данные хранятся в файле XML, то номера кредитных карт или сам файл должен быть зашифрован. Кроме того, данные должны храниться на компьютере, к которому невозможен доступ через Интернет.

На всех компьютерах следует использовать брандмауэры. Правильно сконфигурированные средства защиты могут значительно снизить риск несанкционированного доступа к информации. Отсутствие брандмауэра позволяет злоумышленникам осуществить все виды нападений на ваш сайт, так что эти средства защиты необходимы для любого коммерческого web-сайта.

Тщательно протестируйте вашу систему. Ошибки в системе часто оказываются теми лазейками, из-за которых не срабатывают средства защиты. Этого не произойдет, если система работает без сбоев. Поэтому тестирование системы имеет очень важное значение. Установка средств защиты зависит от программного обеспечения, используемого при реализации системы. Для установки протокола HTTPS необходимо, чтобы web-сервер был правильно сконфигурирован. Для шифрования базы данных также необходимо, чтобы она была правильно сконфигурирована. Мы не будем углубляться в детали установки средств обеспечения безопасности, так как они весьма разнообразны, но важность этого фактора трудно переоценить.

 

Доверие клиента

Если клиент не испытывает доверия к web-сайту, у него не возникнет желания передавать информацию, связанную с его кредитной картой. Между чтением информации на страницах электронного магазина и решением фактически приобрести товар — огромная разница. Можно посоветовать несколько способов повышения доверия клиента к web-сайту.

Качество работы сайта влияет на впечатления клиента от вашего электронного магазина. Если клиент сталкивается с неработающими ссылками или другими очевидными системными ошибками, вряд ли он будет относиться к такому сайту с доверием. Когда речь идет только о поиске информации, то подобные ошибки могут восприниматься достаточно легко, но когда дело доходит до сообщения важной персональной информации, надежная работа сайта становится критически важной.

Доступное изложение принципов работы с персональной информацией также очень важно для формирования доверительного отношения клиента. Если клиент не имеет представления о том, что произойдет с той информацией, которую он должен переслать на ваш сайт, он вряд ли захочет это сделать. Поэтому на сайте следует отвести специальную страницу, где четко объясняется, зачем нужна эта информация и как она будет обрабатываться; кроме того, необходимо, чтобы имелась четко обозначенная ссылка на эту страницу.

Неплохой идеей является предоставление клиенту возможности ознакомиться с теми мерами, которые предприняты для обеспечения безопасности при пересылке информации. Если вы объясните, что вся персональная информация зашифровывается перед отправлением и хранится в безопасном месте, клиент будет больше доверять вашему сайту.

Также на отношение клиента влияет общее впечатление от вашего сайта. Чем лучше выглядит ваш сайт, тем больше доверия он вызовет у посетителя. Оформление сайта, удобство навигации и другие факторы, влияющие на впечатление клиента, также будут влиять и на степень его доверия к сайту. Грамматические ошибки в тексте, неряшливое оформление и неудобство навигации неизбежно оттолкнут потенциальных покупателей.

 

Сбор информации о заказе

Когда покупатель отобрал товары, которые он собирается приобрести, следующим этапом является подсчет стоимости покупки и выполнение заказа. Необходимо получить определенную информацию о покупателе, в том числе его имя, адрес и номер телефона или адрес электронной почты (или установить какой- нибудь другой способ связи с ним). Также покупатель может выбрать один из способов доставки товара. Наконец, самое главное — покупатель должен сообщить номер своей кредитной карты, которой он будет оплачивать покупку.

Мы начнем с изучения классов, которые будут использоваться в JSP-страни- це как компоненты JavaBean. Customerlnfo, Creditlnfo, Fulfillment, Authorization и Order — все это классы, которые содержат информацию, собранную в процессе оформления заказа.

Следующие три класса, которые мы изучим, — TestPaymentAuthorizer, Ship- pi ngCal cul ator и Eraai 1 er — также используются в процессе оформления заказа. Затем мы рассмотрим HTML-страницу, сервлет и несколько JSP-страниц, с помощью которых осуществляется взаимодействие с пользователем при сборе необходимой информации.

 

Класс Customerlnfo

Класс Customerlnfo предназначен для сбора некоторой стандартной информации о покупателе. Имя покупателя и его адрес необходимы для того, чтобы ему можно было доставить заказ, а адрес электронной почты и номер телефона — для того, чтобы можно было связаться с клиентом и сообщить ему о каких-то изменениях или задать какие-либо вопросы. Объект Creditlnfo мы обсудим несколько позже. Класс Customerlnfo состоит только из методов getXxx и setXxx, как показано в листинге 5.1.

Листинг 5.1. Класс Customerlnfo (Customerlnfo.java)

package com.XmlEcomBook.Chap05;
 
 public class CustomerInfo {
 
 private String lastName;
 
 private String firstName;
 
 private String address1;
 
 private String address2;
 
 private String city;
 
 private String state;
 
 private String zip;
 
 private String email;
 
 private String phoneNumber;
 
 private CreditInfo creditInfo;
 
 public CustomerInfo() {
 
 }
 
 public String getLastName() {
 
 return lastName;
 
 }
 
 public void setLastName( String newLastName ) {
 
 lastName = newLastName;
 
 }
 
 public String getFirstName() {
 
 return firstName;
 
 }
 
 public void setFirstName( String newFirstName ) {
 
 firstName = newFirstName;
 
 }
 
 public void setAddress1( String newAddress1 ) {
 
 address1 = newAddress1;
 
 }
 
 public String getAddress1() {
 
 return address1;
 
 }
 
 public void setAddress2( String newAddress2 ) {
 
 address2 = newAddress2;
 
 }
 
 public String getAddress2() {
 
 return address2;
 
 }
 
 public void setCity( String newCity ) {
 
 city = newCity;
 
 }
 
 public String getCity() {
 
 return city;
 
 }
 
 public void setState( String newState ) {
 
 state = newState;
 
 }
 
 public String getState() {
 
 return state;
 
 }
 
 public void setZip( String newZip ) {
 
 zip = newZip;
 
 }
 
 public String getZip() {
 
 return zip;
 
 }
 
 public void setEmail( String newEmail ) {
 
 email = newEmail;
 
 }
 
 public String getEmail() {
 
 return email;
 
 }
 
 public void setPhoneNumber( String newPhoneNumber ) {
 
 phoneNumber = newPhoneNumber;
 
 }
 
 public String getPhoneNumber() {
 
 return phoneNumber;
 
 }
 
 public CreditInfo getCreditInfo() {
 
 return creditInfo;
 
 }
 
 public void setCreditInfo( CreditInfo newCreditInfo ) {
 
 creditInfo = newCreditInfo;
 
 }
 
 }

 

Класс Creditlnfo

В классе Creditlnfo содержится информация о кредитной карте клиента. Сюда входит тип кредитной карты, например Visa или MasterCard, ее номер и дата истечения срока действия. Все эти сведения необходимо сообщить при обращении к поставщику услуг по обработке.

Листинг 5.2. Класс Crediditlnfo (Creditlnfo.java)

package com.XmlEcomBook.Chap05;
 
 public class CreditInfo extends Object {
 
 private String creditCardType;
 
 private String creditCardNumber;
 
 private String expirationDate;
 
 public CreditInfo() {
 
 }
 
 public String getCreditCardType() {
 
 return creditCardType;
 
 }
 
 public void setCreditCardType( String newCreditCardType ) {
 
 creditCardType = newCreditCardType;
 
 }
 
 public String getCreditCardNumber() {
 
 return creditCardNumber;
 
 }
 
 public void setCreditCardNumber( String newCreditCardNumber) 


{
 
 creditCardNumber = newCreditCardNumber;
 
 }
 
 public String getExpirationDate() {
 
 return expirationDate;
 
 }
 
 public void setExpirationDate( String newExpirationDate ) {
 
 expirationDate = newExpirationDate;
 
 }
 
 }

 

Класс Fullfilment

В процесс выполнения заказа входит все, что должно быть сделано с товаром после оформления заказа. Обычно для этого нужно найти товар на складе, запаковать его и отправить клиенту. Мы рассмотрим несколько упрощенный вариант выполнения заказа; в нашем примере будет учитываться только сам процесс доставки.

В классе Fullfilment имеются поля для хранения информации о фирме, которая осуществляет доставку, и о типе услуг. Таким образом, мы можем доставлять товары с помощью различных почтовых фирм — например, Federal Express, UPS или почтовой службы US, а также выбирать различные типы услуг — срочную доставку на следующий день, через один или два дня или доставку в обычном режиме. Также нужно знать, сколько клиент должен заплатить за доставку. Эта сумма добавляется к стоимости товаров, что в результате дает полную стоимость заказа. Когда заказ наконец отправлен, ему должен быть присвоен некоторый идентификационный номер, а также следует записать дату отправки заказа — эти сведения потребуются, если от клиента поступят какие-либо вопросы, связанные с доставкой.

В классе Fullfilmerit (листинг 5.3) имеются методы setXxx и getXxx для каждого из полей. Имеется также один специальный метод, setShipperAndClass. Он позволяет задавать в одной строке и название почтовой фирмы, и тип услуг (для данного заказа) [Эту совокупность далее мы будем называть способом доставки. — Примеч. перев.]. Как вы увидите в разделе «JSP-страница Shippinglnfo», это упрощает обработку введенных пользователем данных (о предпочтительном способе доставки). В этом методе используется объект StringTokenizer, который разделяет строку на две части, затем первую часть заносит в поле shipper (почтовая фирма), а вторую — в поле class (тип услуг). Это сделано для того, чтобы упростить ввод указанных данных. Ниже мы рассмотрим страницу Shippinglnfo.jsp и увидим, как используется данный метод.

Листинг 5.3. Класс Fulfilment (Fullfilment.java)

package com.XmlEcomBook.Chap05;
 
 import java.util.Date;
 
 import java.util.StringTokenizer;
 
 public class Fulfillment {
 
 String shipper; 


//UPS, Fedex, USPS, etc.
 
 String shippingClass; 


//Overnight, 2 Day, regular, frieght, etc.
 
 double costToCustomer; 


//How much the customer is charged for shipping
 
 String trackingNumber = "NO_TRACKING_NUMBER";
 
 String dateSent = "NOT_SENT_YET";
 
 public Fulfillment() {
 
 }
 
 public void setShipper( String newShipper ) {
 
 shipper = newShipper;
 
 }
 
 public String getShipper() {
 
 return shipper;
 
 }
 
 public void setShipperAndClass( String shipperAndClass ) {
 
 StringTokenizer st = new StringTokenizer( shipperAndClass );
 
 if( st.hasMoreTokens() ) {
 
 shipper = st.nextToken();
 
 if( st.hasMoreTokens() ) {
 
 shippingClass = st.nextToken();
 
 }
 
 }
 
 }
 
 public void setShippingClass( String newClass ) {
 
 shippingClass = newClass;
 
 }
 
 public String getShippingClass() {
 
 return shippingClass;
 
 }
 
 public void setTrackingNumber( String newNumber ) {
 
 trackingNumber = newNumber;
 
 }
 
 public String getTrackingNumber() {
 
 return trackingNumber;
 
 }
 
 public void setDateSent( String newDate )
 {
 dateSent = newDate;
 
 }
 
 public String getDateSent() {
 
 return dateSent;
 
 }
 
 public double getCostToCustomer() {
 
 return costToCustomer;
 
 }
 
 public void setCostToCustomer( double newCost ) {
 
 costToCustomer = newCost;
 
 }
 
 }

 

Класс Authorization

Класс Authorization (листинг 5.4) используется для хранения данных, которые возвратил поставщик услуг по обработке. В нем имеются три поля: во-первых, булева переменная, указывающая, было ли получено подтверждение указанных клиентом сведений о кредитной карте. Затем имеется поле, в котором указываются причины отказа (если подтверждение не получено), и, наконец, поле, содержащее код подтверждения (если оно получено). Для всех этих полей имеются методы getXxx и setXxx, с помощью которых можно извлекать и модифицировать значения полей.

Листинг 5.4. Класс Authorization (Authorization.java)

package com.XmlEcomBook.Chap05;
 
 public class Authorization {
 
 private boolean approved = false;
 
 private String reason = "Unknown"; 


//reason for a denial
 
 private String authorizationCode; 


// auth code from patment service
 
 public boolean isApproved() {
 
 return approved;
 
 }
 
 public void setApproved( boolean newApproved ) {
 
 approved = newApproved;
 
 }
 
 public String getReason() {
 
 return reason;
 
 }
 
 public void setReason( String newReason ) {
 
 reason = newReason;
 
 }
 
 public String getAuthorizationCode() {
 
 return authorizationCode;
 
 }
 
 public void setAuthorizationCode( String newAuthCode ) {
 
 authorizationCode = newAuthCode;
 
 }
 
 }

 

Класс Order

Класс Order служит в основном в качестве контейнера для всевозможных сведений, которые мы собираем при оформлении заказа. Сюда входит информация о клиенте, о доставке, номер кредитной карты клиента, перечень заказанных товаров и данные, присланные поставщиком услуг по обработке (в частности, код подтверждения). Нам также понадобится уникальный идентификатор этого заказа, чтобы на него можно было впоследствии ссылаться. Кроме того, нужно указать дату заказа. Все эти сведения вносятся в соответствующие поля класса Order. Конструктор класса задает идентификатор и дату заказа. Метод, используемый для генерации уникального идентификатора, мы исследуем несколько позже. В листинге 5.5 показаны методы getXxx и setXxx для полей класса. Для полей id и date методы setXxx отсутствуют, так как их значения задаются конструктором класса и затем не меняются.

Листинг 5.5. Поля, конструктор и методы setXxx и getXxx для класса Order (Order.java)

package com.XmlEcomBook.Chap05;
 
 import com.XmlEcomBook.catalog.CartItem;
 
 import java.util.*;
 
 import java.io.*;
 
 import com.XmlEcomBook.util.Debug;
 
 public class Order {
 
 private int id; //unique id for this order
 
 private Date date; //date of order
 
 private Vector items = new Vector();
 
 private CustomerInfo customerInfo;
 
 private Authorization authorization; //payment authorization
 
 private Fulfillment fulfillment;
 
 public Order() {
 
 id = getUniqueId();
 
 date = new Date();
 
 }
 
 public int getId() {
 
 return id;
 
 }
 
 public Date getDate() {
 
 return date;
 
 }
 
 public void setItems( Vector newItems ) {
 
 if( newItems != null )
 
 items = newItems;
 
 }
 
 public Vector getItems() {
 
 return items;
 
 }
 
 public void setCustomerInfo( CustomerInfo newCustomer ) {
 
 if( newCustomer != null )
 
 customerInfo = newCustomer;
 
 }
 
 public CustomerInfo getCustomerInfo() {
 
 return customerInfo;
 
 }
 
 public void setAuthorization( Authorization newAuth ) {
 
 authorization = newAuth;
 
 }
 
 public Authorization getAuthorization() {
 
 return authorization;
 
 }
 
 public void setFulfillment( Fulfillment newFulfillment ) {
 
 fulfillment = newFulfillment;
 
 }
 
 public Fulfillment getFulfillment() {
 
 return fulfillment;
 
 }

В листинге 5.6 показаны некоторые методы, оперирующие данными, которые содержатся в классе Order. Первый метод, getTotalltemPrice, реализует цикл по всем заказанным товарам и для каждого товара умножает его цену на количество заказанных экземпляров. Затем подсчитывается и возвращается общая сумма. Метод getOrderTotal добавляет к общей сумме стоимость доставки, что и составляет общую стоимость заказа. Наконец, имеется метод getTotalltemWeight, который аналогичен методу getTotalltemPrice, но только в нем подсчитывается не стоимость, а общий вес заказа. Метод getPrice-осуществляет вспомогательные функции — удаляет дополнительные символы (знак $ и запятые) из строки с указанием цены, полученной из объекта Cartltem, а затем преобразует полученное число к типу doubl e.

Листинг 5.6. Методы для подсчета характеристик заказа как единого целого (Order.java)

public double getTotalItemPrice() {
 
 double total = 0;
 
 Enumeration enum = items.elements();
 
 while( enum.hasMoreElements() ) {
 
 CartItem item = (CartItem)enum.nextElement();
 
 total += getPrice( item ) * item.getNumberOrdered();
 
 }
 
 return total;
 
 }
 
 public double getTotalItemWeight() {
 
 double total = 0;
 
 Enumeration enum = items.elements();
 
 while( enum.hasMoreElements() ) {
 
 CartItem cartItem = (CartItem)enum.nextElement();
 
 double d = Double.parseDouble(cartItem.getShippingValue());
 
 total += d * cartItem.getNumberOrdered();
 
 }
 
 return total;
 
 }
 
 private double getPrice( CartItem item ) {
 
 String s = item.getPrice();
 
 //remove dollar sign
 
 s = s.replace( '$', ' ' );
 
 //remove commas
 
 int i;
 
 while( (i = s.indexOf( ',' )) > 0 ) {
 
 s = s.substring( 0, i ) + s.substring( i + 1 );
 
 }
 
 return Double.parseDouble( s );
 
 }

Имеется также метод для записи заказа в формате 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.7. DTD для описания структуры заказа (order.dtd)

<!ELEMENT order (item*, customer_info, authorization, 
fulfillment )>
 
 <!ATTLIST order id ID #REQUIRED
 
 date CDATA #REQUIRED>
 
 <!ELEMENT item (#PCDATA)>
 
 <!ATTLIST item id NMTOKEN #REQUIRED
 
 quantity NMTOKEN #REQUIRED
 
 price CDATA #REQUIRED>
 
 <!ELEMENT customer_info (first_name, last_name, 
address1, address2,
 
 city, state, zip, email, phone, credit_info )>
 
 <!ELEMENT first_name (#PCDATA)>
 
 <!ELEMENT last_name (#PCDATA)>
 
 <!ELEMENT address1 (#PCDATA)>
 
 <!ELEMENT address2 (#PCDATA)>
 
 <!ELEMENT city (#PCDATA)>
 
 <!ELEMENT state (#PCDATA)>
 
 <!ELEMENT zip (#PCDATA)>
 
 <!ELEMENT email (#PCDATA)>
 
 <!ELEMENT phone (#PCDATA)>
 
 <!ELEMENT credit_info (card_numer, card_type, expiration )>
 
 <!ELEMENT card_number (#PCDATA)>
 
 <!ELEMENT card_type (#PCDATA)>
 
 <!ELEMENT expiration_date (#PCDATA)>
 
 <!ELEMENT authorization (reason?, auth_code?)>
 
 <!ATTLIST authorization approved CDATA #IMPLIED>
 
 <!ELEMENT reason (#PCDATA)>
 
 <!ELEMENT authorization_code (#PCDATA)>
 
 <!ELEMENT fulfillment (backorder_date, shipper, shipping_class,
 
 cost, tracking_number, date_sent)>
 
 <!ELEMENT shipper (#PCDATA)>
 
 <!ELEMENT shipping_class (#PCDATA)>
 
 <!ELEMENT cost (#PCDATA)>
 
 <!ELEMENT tracking_number (#PCDATA)>
 
 <!ELEMENT date_sent (#PCDATA)>

В листинге 5.8 приведен метод, который создает документ XML, соответствующий этому определению DTD. Это примитивный, слишком прямолинейный метод, в котором просто перебираются все поля класса Order и для каждого поля выписываются элементы и атрибуты XML. Такой подход не всегда является оптимальным, так как изменения в классах, входящих в класс Order, приведут к необходимости изменения самого метода. Таким образом, теряются преимущества инкапсуляции, которую обеспечивает объектно-ориентированный подход к программированию. Было бы лучше рассматривать эти классы в единстве. Более удачный метод создания документа XML мы рассмотрим в главе 6.

Листинг 5.8. Метод writeXML (Order.java)

public void writeXML( Writer writer ) {
 
 try {
 
 writer.write( "<?xml version='1.0' ?>" );
 
 writer.write( "<!DOCTYPE order SYSTEM '.."
 
 + File.separator + "order.dtd'>" );
 
 writer.write( "<order id='" + id + "' " );
 
 writer.write( "date='" + date + "'>" );
 
 Enumeration enum = items.elements();
 
 while( enum.hasMoreElements() ) {
 
 CartItem item = (CartItem)enum.nextElement();
 
 writer.write( "<item id='" + item.getId() + "' " );
 
 writer.write( "quantity='" + item.getNumberOrdered() + "' ");
 
 writer.write( "price='" + item.getPrice() + "'>" );
 
 writer.write( item.getName() + "</item>" );
 
 }
 
 writer.write( "<customer_info>\n<first_name>" +
 
 customerInfo.getFirstName() + "</first_name>" +
 
 "\n<last_name>" + customerInfo.getLastName() + "</last_name>" +
 
 "\n<address1>" + customerInfo.getAddress1() + "</address1>" +
 
 "\n<address2>" + customerInfo.getAddress2() + "</address2>" +
 
 "\n<city>" + customerInfo.getCity() + "</city>" +
 
 "\n<state>" + customerInfo.getState() + "</state>" +
 
 "\n<zip>" + customerInfo.getZip() + "</zip>" +
 
 "\n<email>" + customerInfo.getEmail() + "</email>" +
 
 "\n<phone>" + customerInfo.getPhoneNumber() + "</phone>" );
 
 CreditInfo credit = customerInfo.getCreditInfo();
 
 writer.write( "\n<credit_info>\n<card_number>" +
 
 credit.getCreditCardNumber() + "</card_number>" +
 
 "\n<card_type>" + credit.getCreditCardType() + "</card_type>" +
 
 "\n<expiration_date>" + credit.getExpirationDate() +
 
 "</expiration_date>\n</credit_info>\n</customer_info>" );
 
 
 writer.write( "\n<authorization approved='" +
 
 authorization.isApproved() + "'>" +"\n<reason>" +
 
 authorization.getReason() + "</reason>\n<authorization_code>" +
 
 authorization.getAuthorizationCode() + "</authorization_code>" +
 
 "</authorization>" );
 
 writer.write( "\n<fulfillment>\n" +
 
 "\n<shipper>" + fulfillment.getShipper() + "</shipper>" +
 
 "\n<class>" + fulfillment.getShippingClass() + "</class>" +
 
 "\n<cost>" + fulfillment.getCostToCustomer() + "</cost>" +
 
 "\n<tracking_number>" + fulfillment.getTrackingNumber() +
 
 "</tracking_number>\n<date_sent>" +
 
 fulfillment.getDateSent() + "</date_sent>\n</fulfillment>" );
 
 writer.write( "\n</order>" );
 
 }
 
 catch( IOException e ) {
 
 }
 
 }

Последний метод в классе Order, названный getllniqueld, приведен в листинге 5.9. Он генерирует уникальный идентификатор заказа. В нашем случае мы используем счетчик, который увеличивается на единицу каждый раз, когда нам требуется новый идентификатор. Этот счетчик должен храниться постоянно, чтобы мы могли быть уверенны в уникальности присваиваемых идентификаторов даже после полной перезагрузки системы. Хранение счетчика в памяти — в данном случае не выход из положения, так как при каждой перезагрузке системы счетчик начинает повторять уже присвоенные ранее идентификаторы. В качестве постоянного места хранения счетчика мы используем специальный файл.

Листинг 5.9. Метод getUniqueld (Order.java)

synchronized private int getUniqueId() {
 
 int id;
 
 try {
 
 ObjectInputStream in = new ObjectInputStream( new
 
 FileInputStream( "orderID.txt" ) );
 
 id = in.readInt();
 
 }
 
 catch( IOException e ) {
 
 id = 1000;
 
 }
 
 try {
 
 ObjectOutputStream out = new ObjectOutputStream( new
 
 FileOutputStream( "orderID.txt" ) );
 
 out.writeInt( id + 1 );
 
 out.close();
 
 }
 
 catch( IOException e ) {
 
 }
 
 return id;
 
 }
 
 }

 

Класс TestPaymentAuthorizer

Следующие классы, которые мы будем рассматривать, используются в процессе оформления заказа. Первый из них занимается проверкой данных о кредитной

карте клиента. В этом примере мы создали очень простой класс, который возвращает код подтверждения в зависимости от последней цифры номера кредитной карты, содержащегося в классе Order. В настоящем электронном магазине вместо этого класса должен быть подставлен другой, который передает данные о кредитной карте поставщику услуг по обработке. Способ передачи этих данных в большой степени зависит от конкретного поставщика.

Класс TestPaymentAuthori zer представлен в листинге 5.10. Первый метод в этом классе, getAuthorization, в качестве параметра получает объект Order, из которого извлекается информация о кредитной карте для проверки. В нашем примере мы просто берем последнюю цифру номера и, если это 1, карта с таким номером отклоняется, то есть считается не прошедшей проверку. Этот абстрактный, произвольный критерий мы используем только для того, чтобы протестировать работу метода и продемонстрировать оба типа возвращаемых значений.

Метод capture нужен для того, чтобы завершить процесс снятия денег со счета клиента, осуществляемый поставщиком услуг по обработке. В нашем случае этот метод ничего не делает, но, опять-таки, в настоящем магазине он использовался бы для сообщения поставщику о том, что следует завершить процесс оплаты. Если бы мы хотели автоматизировать процесс возвращения денег в случае, когда клиент возвращает товар, или процесс разблокировки счета клиента, если заказанного товара не оказалось в наличии, то соответствующие методы следовало бы тоже поместить в класс TestPaymentAuthori zer.

Листинг 5.10. Класс TestPaymentAuthorizer (TestPaymentAuthorizer.java)

public class TestPaymentAuthorizer {
 
 static public Authorization getAuthorization( Order order ) {
 
 Authorization authorization = new Authorization();
 
 try {
 
 CustomerInfo custInfo = order.getCustomerInfo();
 
 CreditInfo creditInfo = custInfo.getCreditInfo();
 
 String num = creditInfo.getCreditCardNumber();
 
 if( num != null ) {
 
 if( num.endsWith( "1" ) ) {
 
 authorization.setApproved( false );
 
 authorization.setReason("Insufficent Funds");
 
 }
 
 else
 
 {
 
 authorization.setApproved( true );
 
 authorization.setReason( "Approved" );
 
 authorization.setAuthorizationCode( "Test" );
 
 }
 
 }
 
 }
 
 catch( Exception e ) {}
 
 return authorization;
 
 }
 
 static public void capture( String authorizationCode, double 
amount ) {
 
 }
 
 }

 

Класс ShippingCalculator

Теперь нам нужен какой-нибудь способ подсчета стоимости доставки товара заказчику. Эта сумма зависит от нескольких факторов, главными из которых являются выбранная клиентом почтовая фирма и тип услуг. На стоимость также могут влиять вес посылки и расстояние до пункта назначения. Мы при вычислении общей стоимости будем учитывать только три фактора: почтовую фирму, тип услуг и вес посылки. Объекту ShippingCalculator в качестве параметра передается объект Order, в котором содержится вся необходимая информация о заказе: вес посылки и адрес пункта назначения.

Первый метод, getTypes, возвращает массив, в котором перечислены все типы услуг, предоставляемые каждой почтовой фирмой, сотрудничающей с магазином. Второй метод, getPrice, возвращает цену конкретного типа доставки конкретной фирмой. Входным параметром этого метода должна быть одна из строк массива, возвращенного методом getTypes.

Метод getPrice (листинг 5.11) можно расширить, чтобы учитывать при вычислении стоимости доставки большее количество факторов, чем перечисленные выше (вес посылки и способ доставки). Кроме того, было бы неплохо организовать считывание информации в этот класс из некоторого источника данных, например файла XML или базы данных, с последующим вычислением стоимости. Это позволило бы динамически менять указанные цифры в соответствии с реальными колебаниями цен, не меняя самого кода.

Листинг 5.11. Начало кода класса ShippingCalculator и его конструктора (ShippingCalculator.java)

public class ShippingCalculator {
 
 Order order;
 
 public ShippingCalculator( Order setOrder ) {
 
 order = setOrder;
 
 }
 
 public String[] getTypes() {
 
 String[] names = { "FedEx Overnight",
 
 "FedEx 2-Day",
 
 "UPS Overnight",
 
 "UPS 3-Day",
 
 "USPS 2-Day",
 
 "USPS Regular" };
 
 return names;
 
 }
 
 public String getPrice( String name ) {
 
 double weight = order.getTotalItemWeight();
 
 if( name.equals( "FedEx Overnight" ) )
 
 if( weight > 3.0 )
 
 return "$10.99";
 
 else
 
 return "$7.99";
 
 if( name.equals( "FedEx 2-Day" ) )
 
 if( weight > 3.0 )
 
 return "$5.99";
 
 else
 
 return "$3.49";
 
 if( name.equals( "UPS Overnight" ) )
 
 if( weight > 2.0 )
 
 return "$8.99";
 
 else
 
 return "$6.99";
 
 if( name.equals( "UPS 3-Day" ) )
 
 if( weight > 2.5 )
 
 return "$5.99";
 
 else
 
 return "$4.99";
 
 if( name.equals( "USPS 2-Day" ) )
 
 if( weight > 2.5 )
 
 return "$4.99";
 
 else
 
 return "$3.99";
 
 if( name.equals( "USPS Regular" ) )
 
 return "$2.99";
 
 return "0.00";
 
 }
 
 }

 

Класс Emailer

Класс Emailer используется для отправки электронных сообщений клиенту. Эти сообщения могут содержать подтверждение заказа или информацию о доставке. В этом классе имеются две статические переменные, необходимые для его конфигурирования. Первая переменная — имя сервера SMTP (Simple Mail Transfer Protocol — простой протокол электронной почты), который используется данным магазином для отправки почты. Вторая переменная — электронный адрес, который будет указан в письмах клиенту в качестве обратного, то есть в поле From (От). В нашем примере мы используем формат, в котором указывается как название фирмы XMLGifts, так и ее электронный адрес (orders® xmlgifts.com). Прежде чем использовать код, приведенный на прилагаемом к нашему курсу каталоге файлов, вы, разумеется, должны заменить эти данные теми, которые фактически фигурируют в вашей системе. Имя сервера SMTP, используемого для пересылки электронной почты, можно найти в параметрах конфигурации вашей почтовой программы. В листинге 5.12 показано начало кода класса Emailer.

Листинг 5.12. Начало кода класса Emailer (Emailer.java)

package com.XmlEcomBook.Chap05;
 
 import java.util.*;
 
 import java.io.*;
 
 import javax.mail.*;
 
 import javax.mail.internet.*;
 
 public class Emailer {
 
 static final String host = "SMTP-HOST-NAME";
 
 static final String from = "XMLGifts<orders@xmlgifts.com>";

Первый метод в этом классе используется для сообщения клиенту об отправке ему посылки с заказом. Хотя это подтверждение не является абсолютно необходимым, оно имеет большое значение, так как клиент, получив такое сообщение, будет уверен, что его заказ действительно выполняется, а также найдет ответы на возможные вопросы о доставке заказа. В этом методе после получения информации о пользователе из объекта класса Order мы вызываем служебный метод под названием <jetMessage, передавая ему в качестве параметра электронный адрес клиента. Метод getMessage создает объект Message с помощью интерфейса API JavaMail, о чем будет подробнее сказано далее в этом разделе. В объекте Message указывается тема сообщения и вносится текст, после чего письмо отправляется. Отправка письма осуществляется с помощью метода send объекта Transport из интерфейса API JavaMail. Этот метод создает простое сообщение (листинг 5.13), в котором указывается идентификатор заказа, чтобы клиент мог в дальнейшем на него ссылаться. Метод можно легко расширить, чтобы включить более детальную информацию о заказе.

Листинг 5.13. Метод sendConfiramtion (Emailer.java)

public static void sendConfirmation(Order order) {
 
 try {
 
 CustomerInfo cust = order.getCustomerInfo();
 
 Message msg = getMessage( cust.getEmail() );
 
 msg.setSubject("XMLGifts.com Order Confirmation");
 
 msg.setText("Your order is being processed");
 
 msg.setText("Your order number is:" + order.getId() );
 
 Transport.send(msg);
 
 }
 
 catch (MessagingException mex) {
 
 }
 
 }

Метод sendShipped (листинг 5.14) аналогичен методу sendConfirmation, отличие касается только текста посылаемого сообщения. /

Листинг 5.14. Метод sendShipped (Emailer.java)

 public static void sendShipped(String email, String orderId ) {
 
 try {
 
 Message msg = getMessage( email );
 
 msg.setSubject("Your XMLGifts.com Order has shipped");
 
 msg.setText("Order number " + orderId + " has shipped" );
 
 Transport.send(msg);
 
 }
 
 catch (MessagingException mex) {
 
 }
 
 }

Метод getMessage используется другими методами класса для осуществления большинства действий, необходимых при работе с интерфейсом API JavaMail. Аргументом этого метода является электронный адрес клиента, которому посылается сообщение. В первую очередь в этом методе создается новый объект Session, а его значением становится имя сервера SMTP, которое, как вы помните, берется из статической переменной класса Emailег. Затем создается новый объект Message и устанавливаются значения полей, отведенных для адресов отправителя и получателя сообщения, а также для текущей даты (на которую можно впоследствии ссылаться как на дату отправки сообщения).

Интерфейс прикладных программ (API) JavaMail — это набор классов, которые моделируют систему электронной почты и являются стандартным расширением Java. Этот интерфейс можно использовать для получения и отправления сообщений с помощью стандартных почтовых протоколов. Более подробную информацию вы найдете по адресу http://java.sun.com/products/javamail, и оттуда же вы сможете бесплатно загрузить версию 1.2 этого интерфейса API. Метод getMessage (листинг 5.15) использует интерфейс JavaMail для создания нового объекта Message, в котором указаны адреса отправителя и получателя, а также текущая дата.

Листинг 5.15. Метод getMessage (Emailer.java)

static Message getMessage( String toEmail ) throws 
MessagingException {
 
 Properties props = new Properties();
 
 props.put("mail.smtp.host", host);
 
 Session session = Session.getDefaultInstance(props, null);
 
 session.setDebug(true);
 
 Message msg = new MimeMessage(session);
 
 msg.setFrom(new InternetAddress(from));
 
 InternetAddress[] address = {new InternetAddress(toEmail)};
 
 msg.setRecipients(Message.RecipientType.TO, address);
 
 msg.setSentDate(new Date());
 
 return msg;
 
 }
 
 }

 

Страница Customerlnfo

Теперь мы перейдем к классам, с помощью которых осуществляется получение всей информации от клиента и передача ее рассмотренным выше классам. В первую очередь — это HTML-страница Customerlnfo.html. На этой странице имеется форма, поля которой предназначены для введения информации пользователем и соответствуют полям класса Customerlnfo (листинг 5.16). Как будет видно на JSP-странице Shippinglnfo, это соответствие упрощает передачу данных из формы в класс.

Листинг 5.16. Страница Customerlnfo (Customerlnfo.html)

<html>
 
 <head>
 
 <title>Customer Info</title>
 
 </head>
 
 <body>
 
 <form action="ShippingInfo.jsp">
 
 <p>
 
 First Name:<input name="firstName" />
 
 Last Name:<input name="lastName" />
 
 </p>
 
 <p>
 
 Address line 1:<input name="address1" /><br />
 
 Address line 2:<input name="address2" /><br />
 
 City:<input name="city" />
 
 State:<input size="2" name="state" />
 
 Zip:<input size="10" name="zip" />
 
 </p>
 
 <p>Email Address:<input name="email" /><br /></p>
 
 <p>Phone Number:<input size="13" name="phoneNumber" />
<br /></p>
 
 <input type="submit" value="Submit Information" />
 
 </form>
 
 </body>
 
 </html>

 

JSP-страница Shippinglnfo

После импорта необходимых классов для получения нового объекта класса Custo- merlnfo, связанного с текущим сеансом, используется элемент jsp:useBean. Затем свойства этого элемента с помощью элемента jsp:setProperty устанавливаются равными значениям, введенным в форму на странице Customerlnfo.html. После этого мы получаем класс Order, связанный с текущим сеансом, и вектор Vector, в котором содержится перечень всех заказанных товаров. Потом с помощью скриптлета [Скриптлетом (scriptlet) авторы называют код JSP внутри тегов <%...%>, по-видимому, по аналогии с апплетом и сервлетом (еще одним «изобретением» автора). — Примеч. ред. ] JSP вызываются методы setCustomerlnfo и setltems, которые добавляют соответствующие объекты в объект Order, как показано в листинге 5.17.

Листинг 5.17. Начало кода Shippinglnfo JSP (Shippinglnfo.jsp)

<%@ page import="com.XmlEcomBook.Chap05.*,java.util.*" %>
 
 <jsp:useBean scope="session" id="custInfo" 
class="CustomerInfo" />
 
 <jsp:setProperty name="custInfo" property="*" />
 
 <jsp:useBean id="order" scope="session" class="Order" />
 
 <jsp:useBean id="theorder" scope="session" class="Vector" />
 
 <% order.setCustomerInfo( custInfo );
 
 order.setItems( theorder );
 
 %>

Затем JSP-страница выдает код HTML, который позволяет пользователю выбрать один из предложенных способов доставки. В этом коде используется объект ShippingCalculator, рассмотренный нами выше в этой главе. Скриптлет, встроенный в код HTML, создает объект ShippingCalculator, а затем с помощью метода getTypes предлагает несколько способов доставки. На этом этапе создается ряд переключателей (radio buttons), по одному на каждый из указанных способов. Это делается с помощью цикла for. Для каждого способа создается элемент input типа radio. Атрибут value (значение) элемента устанавливается с помощью выражения JSP "<t=types[i]X>". Затем такое же выражение используется для отображения этого значения на странице. Другой скриптлет обеспечивает получение данных о стоимости того или иного способа доставки с помощью метода getPrice объекта ShippingCalculator, как показано в листинге 5.18.

Листинг 5.18. Код HTML, который формируется в JSP-странице Shippinglnfo (Shippinglnfo.jsp)

<html>
 
 <head>
 
 <title>Shipping Info</title>
 
 </head>
 
 <body>
 
 <form action="CreditInfo.jsp">
 
 Select a Shipper and Class:<br />
 
 <table>
 
 <% ShippingCalculator calc = new ShippingCalculator( order );
 
 String[] types = calc.getTypes();
 
 for( int i = 0; i < types.length; i++ ) {
 
 %>
 <tr><td><input type="radio" name="shipperAndClass" 
value="<%=types[i] %>" /><%=types[i] %></td>
 
 <td><%=calc.getPrice(types[i]) %></td></tr>
 
 <% } %>
 
 </table>
 
 <input type="submit" value="Submit information">
 
 </form>
 
 </body>
 
 </html>

 

JSP-страница Creditlnfo

Объект Shippinglnfo, связанный с определенным сеансом, создается в JSP-странице Creditlnfo. Информация о доставке, которая была введена в форму в JSP- странице Shippinglnfo, используется в JSP-странице Creditlnfo. Выбранный способ доставки заносится в параметр с именем shipperAndClass, а затем элемент jsp:setProperty вызывает метод setShipperAndClass объекта Shippinglnfo со значением этого параметра. Как уже говорилось ранее, при этом задается сразу и почтовая фирма, и вид доставки, то есть поля shipper и shippingClass (листинг 5.19).

Листинг 5.19. Указание способа доставки (Creditlnfo.jsp)

 <%@ page import="com.XmlEcomBook.Chap05.*" %>
 
 <jsp:useBean scope="session" id="shippingInfo" 
class="Fulfillment" />
 
 <jsp:setProperty name="shippingInfo" property="*" />

В этой JSP-странице сначала задается объект Fullfilment, связанный с данным сеансом и содержащийся в объекте Order. Также создается объект ShippingCalculator, который используется для подсчета выбранного способа доставки. После того как знак $ убран из строки с указанием цены, Shippinglnfo преобразуется к типу double и используется для вызова метода setCostToCustomer объекта Shippinglnfo (листинг 5.20).

Листинг 5.20. Определение стоимости доставки (Creditlnfo.jsp)

<jsp:useBean scope="session" id="order" class="Order" />
 
 <% order.setFulfillment( shippingInfo );
 
 ShippingCalculator calc = new ShippingCalculator( order );
 
 String s = request.getParameter( "shipperAndClass" );
 
 String price = calc.getPrice( s );
 
 price = price.replace( '$', ' ' );
 
 shippingInfo.setCostToCustomer
( Double.parseDouble( price ) );%>

Код HTML этой JSP-страницы используется для сбора необходимой информации о кредитной карте клиента. В первую очередь мы хотели бы отобразить в таблице полностью всю сумму, которую мы собираемся снять со счета клиента. Мы показываем общую стоимость покупки, стоимость доставки и суммарную стоимость заказа. Далее выводится форма, в которой клиент указывает тип своей кредитной карты, номер и дату окончания срока действия, как показано в листинге 5.21.

Листинг 5.21. Код HTML, который формируется в JSP-странице Creditlnfo (Creditlnfo.jsp)

<html>
 
 <head><title>Credit Card Information</title></head>
 
 <body>
 
 Your order price<br />
 
 <table>
 
 <tr><td>Items</td><td><%=order.getTotalItemPrice()%>
</td></tr>
 
 <tr><td>Shipping</td><td><%=price%></td></tr>
 
 <tr bgcolor="yellow"><td>Total</td><td>
<%=order.getOrderTotal()%></td></tr>
 
 </table>
 
 Please enter your credit card information:
 
 <form action="ConfirmInfo.jsp">
 
 <p>
 
 Credit Card Type:
 
 <input type="radio" name="creditCardType" value="Visa">
 
 Visa
 
 </input>
 
 <input type="radio" name="creditCardType" 
value="Master Card">
 
 Master Card
 
 </input>
 
 <input type="radio" name="creditCardType"
 value="American Express">
 
 American Express
 
 </input>
 
 <input type="radio" name="creditCardType" value="Discover">
 
 Discover
 
 </input>
 
 </p>
 
 <p>Credit Card Number:<input name="creditCardNumber" />
</p>
 
 <p>Expiration Date:<input name="expirationDate" /></p>
 
 <input type="submit" value="Submit information">
 
 </form>
 
 </body>
 
 </html>

 

JSP-страница Confirmlnfo

Первое, что мы делаем в JSP-странице Confirmlnfo, — это помещаем информацию, введенную в форму на JSP-странице Creditlnfo, в объект Creditlnfo. При этом используются элементы jsp:useBean и jsp:setProperty, как и в двух предыдущих JSP-страницах. После того как получен объект Order, скриптлет извлекает из него объект Customer-Information, а затем вызывается метод setCreditlnfo, чтобы записать полученные значения, как показано в листинге 5.22.

Листинг 5.22. Запись данных кредитной карты (Confirmlnfo.jsp)

 <%@ page import="com.XmlEcomBook.Chap05.*" %>
 
 <jsp:useBean scope="session" id="creditInfo" 
class="CreditInfo" />
 
 <jsp:setProperty name="creditInfo" property="*" />
 
 <jsp:useBean scope="session" id="order" class="Order" />
 
 <% CustomerInfo cust = order.getCustomerInfo();
 
 cust.setCreditInfo( creditInfo );
 
 %>

Код HTML этой страницы вновь отображает все введенные клиентом данные. Это позволяет клиенту проверить всю введенную им информацию до того, как она будет окончательно отправлена на сервер поставщика для получения подтверждения. Для этого берутся объекты Customerlnfo и Fullfilment, связанные с данным сеансом, и с помощью элементов jsp:getProperty из них извлекаются различные параметры заказа, которые затем отображаются на странице. Внизу страницы располагается кнопка, которая позволяет клиенту отправить данные на сервер, если он не обнаружил ошибок. Чтобы исправить неверно введенные данные, клиент может воспользоваться кнопкой Back (Назад) в окне браузера. Листинг 5.23 содержит код для отображения и проверки введенных клиентом данных.

Листинг 5.23. Отображение информации для ее подтверждения клиентом (Confirmlnfo.jsp)

<html>
 
 <head><title>Confirm Info</title></head>
 
 <body>
 
 <jsp:useBean scope="session" id="custInfo" 
class="CustomerInfo" />
 
 <jsp:useBean scope="session" id="shippingInfo" 
class="Fulfillment" />
 
 
 <p>Verify the information you entered:</p>
 
 <p>Name: <b><jsp:getProperty name="custInfo" 
property="firstName" />
 
 <jsp:getProperty name="custInfo" property="lastName" /></b>
 
 </p>
 
 <p>
 
 Address:<br />
 
 <b><jsp:getProperty name="custInfo" property="address1" />
<br />
 
 <jsp:getProperty name="custInfo" property="address2" /><br />
 
 <jsp:getProperty name="custInfo" property="city" />,
 
 <jsp:getProperty name="custInfo" property="state" />
 
 <jsp:getProperty name="custInfo" property="zip" />
 
 </b></p>
 
 <p>Email: <b><jsp:getProperty name="custInfo" 
property="email" /></b></p>
 
 <p>Phone Number: <b><jsp:getProperty name="custInfo" 
property="phoneNumber" />
 
 </b></p>
 
 <p>
 
 Credit Card Type : <b><jsp:getProperty name="creditInfo"
 
 property="creditCardType" /></b><br />
 
 Credit Card Number: <b><jsp:getProperty name="creditInfo"
 
 property="creditCardNumber" /></b><br />
 
 Expiration Date : <b><jsp:getProperty name="creditInfo"
 
 property="expirationDate" /></b>
 
 </p>
 
 <p>
 
 Shipper: <b><jsp:getProperty name="shippingInfo"
 
 property="shipper" /></b><br />
 
 Class : <b><jsp:getProperty name="shippingInfo"
 
 property="shippingClass" /></b>
 
 </p>
 
 <b><i>Press the back button on your browser to 
correct any information.</i></b>
 
 <form action="servlet/SubmitOrder">
 
 <input type="submit" value="Submit Order" />
 
 </form>
 
 </body>
 
 </html>

 

Сервлет SubmitOrder

Когда подтвержденные клиентом данные (то есть JSP-страница Confirmlnfo) отправлены, необходимо послать поставщику услуг по обработке сведения, связанные с оплатой заказа. Это делается с помощью сервлета SubmitOrder. Здесь мы используем не JSP-страницу, а сервлет, поскольку данная процедура, с одной стороны, требует довольно много кода, а с другой стороны, генерирует сравнительно немного выходных данных. Дело в том, что, как правило, создавать и отлаживать сервлеты проще, чем JSP-страницы, но отрицательной стороной сер- влетов является сложность генерируемого кода HTML.

Главная точка входа в сервлет — метод doGet, который получает объект Session, соответствующий текущему сеансу (листинг 5.24). Затем мы получаем объект Order, сформированный для этого сеанса предыдущими JSP-страницами. Далее для получения подтверждения данных кредитной карты используется класс TestPaymentAuthorizer. Если подтверждение получено, клиенту посылается соответствующее сообщение с помощью класса Emailег, вызывается метод, который записывает заказ в специальный файл, и вызывается JSP-страница Approved.jsp, создающая сообщение с информацией о подтверждении заказа и указанием идентификатора заказа. Если подтверждение не было получено, вызывается JSP-страница Declined .jsp и создается другое сообщение.

Листинг 5.24. Метод doGet сервлета SubmitOrder (SubmitOrder.java)

import java.io.*;
 
 import java.util.*;
 
 import javax.servlet.*;
 
 import javax.servlet.http.*;
 
 import com.XmlEcomBook.Chap05.*;
 
 // Explain why we used a servlet: easier to code, debug
 
 public class SubmitOrder extends HttpServlet {
 
 public void doGet(HttpServletRequest req,
 
 HttpServletResponse res)
 
 throws IOException, ServletException {
 
 res.setContentType("text/html");
 
 PrintWriter out = res.getWriter();
 
 try {
 
 HttpSession session = req.getSession();
 
 Order order = (Order)session.getAttribute( "order" );
 
 Authorization auth = 
TestPaymentAuthorizer.getAuthorization(order );
 
 order.setAuthorization( auth );
 
 if( auth.isApproved() ) {
 
 //Emailer.sendConfirmation( order );
 
 writeOrder( order );
 
 getServletContext()
 
 .getRequestDispatcher("/Approved.jsp").forward(req, res);
 
 }
 
 else {
 
 getServletContext()
 
 .getRequestDispatcher("/Declined.jsp").forward(req, res);
 
 }
 
 }
 
 catch( Exception e )
 
 {
 
 e.printStackTrace(out);
 }
 }

Метод writeOrder используется для записи информации о заказе в файл XML. Этот метод помещает все файлы с заказами, поступившими в течение одного дня, в отдельную папку. Поэтому для определения даты (год, месяц и число месяца) создается специальный объект, GregorianCalendar. В имени папки указывается соответствующая дата, а название файла содержит идентификатор заказа. Метод mkdir класса File вызывается для проверки наличия данной папки, а затем с помощью метода writeXML объекта Order информация о заказе заносится в файл, как показано в листинге 5.25.

Листинг 5.25. Метод writeOrder (SubmitOrder.java)

private void writeOrder( Order order ) {
 
 try
 
 {
 
 Calendar calendar = new GregorianCalendar();
 
 int day = calendar.get( Calendar.DAY_OF_MONTH );
 
 int month = calendar.get( Calendar.MONTH ) + 1;
 
 int year = calendar.get( Calendar.YEAR );
 
 String dir = "Orders_" + year + "-" + month + "-" + day;
 
 String filename = "Order_" + order.getId() + ".xml";
 
 File file = new File( dir );
 
 file.mkdir();
 
 FileWriter writer = new FileWriter( dir + File.separator + filename );
 
 order.writeXML(writer);
 
 writer.close();
 
 }
 
 catch( IOException e ) {
 
 }
 
 }
 
 }

 

JSP-страница Approved

Эта страница вызывается из сервлета SubmitOrder, когда заказ получает подтверждение поставщика услуг по обработке. Эта простая страница включает в себя идентификатор заказа (листинг 5.26); ее можно использовать как квитанцию и при необходимости распечатать данные заказа. Так как у нас имеется объект Order с полной информацией о заказе, в страницу Approved можно включить помимо идентификатора и другие характеристики заказа.

Листинг 5.26. JSP-страница Approved (Approved.jsp)

<%@ page import="com.XmlEcomBook.Chap05.*" %>
 
 <html>
 
 <head><title>Approved Order</title></head>
 
 <body>
 
 <jsp:useBean id="order" scope="session" class="Order" />
 
 Your order has been approved.
 
 Your order number is: <jsp:getProperty name="order" 
property="id" />
 
 </body>
 
 </html>

 

JSP-страница Declined

JSP-страница Declined формируется, если по какой-либо причине кредитная карта клиента не прошла проверку поставщика. Страница генерирует сообщение, в котором указывается эта причина.

Листинг 5.27. JSP-страница Declined (Declined.jsp)

<%@ page import="com.XmlEcomBook.Chap05.*" %>
 
 <html>
 
 <head><title>Credit Card Declined</title></head>
 
 <body>
 
 <jsp:useBean id="order" scope="session" class="Order" />
 
 Your credit card was declined.<br />
 
 The reason given was:
 
 <% Authorization auth = order.getAuthorization();
 
 if( auth != null ) {
 
 out.println( auth.getReason() );
 
 }
 
 %>
 
 </body>
 
 </html>

 

Обновление информации о доставке

После того как клиент ввел и подтвердил информацию о заказе, отдел доставки электронного магазина должен иметь возможность просматривать эту информацию и обновлять значения таких характеристик, как номер заказа и дата отправки заказа клиенту. Мы также предложим способ формирования списка всех заказов, поступивших в конкретный день, и выбора из этого списка определенного заказа.

 

JSP-страница OrderDateSelector

Простая JSP-страница OrderDateSelector (листинг 5.28) отображает форму с единственным полем ввода. В этом поле по умолчанию указана текущая дата, но пользователь (в данном случае работник отдела доставки) может ввести другую дату. Эта JSP-страница является точкой входа в процесс обновления информации о доставке.

Листинг 5.28. JSP-страница OrderDateSelector (OrderDateSelector.jsp)

 <%@ page import="java.util.*" %> 
 <html> 
 <head><title>0rder Date Selector</title></head> 
 <body> 
 <% Calendar calendar = new GregorianCalendar(); 
 int day = calendar.get( Calendar.DAY_OF_HONTH ); 
 int month = calendar.get( Calendar.MONTH ) + 1; 
 int year = calendar.get( Calendar.YEAR ); %> 
<form action="SelectOrder.jsp"> 
Select a date:
<input name="date" value=" 
 <%= new String( year + "-" + month + "-" + day ); %>"> 
 <br /xinput type="submit" value="Get Orders for Date"> 
 </form> 
 </input> 
 </body> 
 </html> 

 

JSP-страница SelectOrder

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>

Листинг 5.29. JSP-страница SelectOrder (SelectOrder.jsp)

<%@ page import="java.io.*" %>
 
 <html>
 
 <head><title>Select Order</title></head>
 
 <body>
 
 <%
 
 String date = request.getParameter( "date" );
 
 File dir = new File( "Orders_" + date );
 
 File[] files = dir.listFiles();
 
 for( int i = 0; i < files.length; i++ ) {
 
 String name = files[i].getName();
 
 if( name.endsWith( ".xml" ) ) {
 
 int start = name.indexOf( '_' ) + 1;
 
 int end = name.indexOf( '.' );
 
 String orderNum = name.substring( start, end );
 
 %>
 
 <a href="ShowOrder.jsp?dir=<%= dir %>&file=<%= name %> ">
 
 <%= orderNum %>
 
 </a><br />
 
 <% }
 
 }
 
 %>
 
 </body>
 
 </html>

 

JSP-страница ShowOrder

Эта страница отображает данные о заказе, который был выбран пользователем для просмотра. Для создания объектной модели документа задействуются выбранные с помощью описанной выше страницы файл и папка. Используя скрипт- леты (код внутри тегов <%..%>), мы производим анализ файла с помощью стандартных методов DOM. Результат этого разбора записывается в JSP-выражения (код внутри тегов <*=!...*>). Страница ShowOrder представлена в листинге 5.30. Хотя ее код довольно длинный, многие кодовые фрагменты повторяются.

Листинг 5.30. JSP-страница ShowOrder (ShowOrder.jsp)

<%@ page
 
 import="javax.xml.parsers.*,java.util.*,java.io.*,org.w3c.dom.*,
org.xml.sax.*"
 
 %>
 
 <html>
 
 <head><title>Order</title></head>
 
 <body>
 
 <%
 
 double price = 0.0;;
 
 String dir = request.getParameter( "dir" );
 
 String file = request.getParameter( "file" );
 
 Document document = null;
 
 DocumentBuilderFactory factory
 
 = DocumentBuilderFactory.newInstance();
 
 try {
 
 DocumentBuilder builder = factory.newDocumentBuilder();
 
 document = builder.parse( new File( dir, file ) );
 
 }
 
 catch( ParserConfigurationException pce ) {
 
 throw new IOException( "Parser Configuration Error" );
 
 }
 
 catch( SAXException se ) {
 
 throw new IOException( "Parsing Excpetion" );
 
 }
 
 Element order = document.getDocumentElement();
 
 String id = order.getAttribute( "id" );
 
 %>
 
 <h1>Order #<%=id%></h1>
 
 <h2>Items</h2>
 
 <table border="1">
 
 <tr><th>Item</th><th>Description</th><th>Quantity</th>
<th>Price</th></tr>
 
 <% NodeList items = order.getElementsByTagName( "item" );
 
 int numItems = items.getLength();
 
 for( int i = 0;i < numItems; i++ ) {
 
 Element item = (Element)items.item( i );
 
 %>
 
 <tr><td><%=item.getAttribute( "id" )%></td>
 
 <td><%=item.getFirstChild().getNodeValue()%></td>
 
 <td><%=item.getAttribute( "quantity" )%></td>
 
 <td><%=item.getAttribute( "price" )%></td>
 
 <%String priceString = item.getAttribute( "price" );
 
 priceString = priceString.replace( '$', ' ' );
 
 price += Double.parseDouble( priceString ); %>
 
 </tr>
 
 <% }%>
 
 </table>
 
 <% NodeList n1 = order.getElementsByTagName
( "customer_info" );
 
 Element cust = (Element)n1.item( 0 );
 
 Node firstName = cust.getElementsByTagName
( "first_name").item(0);
 
 Node lastName = cust.getElementsByTagName
( "last_name" ).item(0);
 
 Node address1 = cust.getElementsByTagName
( "address1" ).item(0);
 
 Node address2 = cust.getElementsByTagName
( "address2" ).item(0);
 
 Node city = cust.getElementsByTagName( "city" ).item(0);
 
 Node state = cust.getElementsByTagName( "state" ).item(0);
 
 Node zip = cust.getElementsByTagName( "zip" ).item(0);
 
 Node email = cust.getElementsByTagName( "email" ).item(0);
 
 Node phone = cust.getElementsByTagName( "phone" ).item(0);
 
 %>
 
 <h2>Customer Information</h2>
 
 Name:
 
 <%=firstName.getFirstChild().getNodeValue()%>
 
 <%=lastName.getFirstChild().getNodeValue()%><br /><br />
 
 Address:<br />
 
 <%=address1.getFirstChild().getNodeValue()%><br/ >
 
 <%=address2.getFirstChild().getNodeValue()%><br />
 
 <%=city.getFirstChild().getNodeValue()%>
 
 <%=state.getFirstChild().getNodeValue()%>
 
 <%=zip.getFirstChild().getNodeValue()%><br /><br />
 
 Email:<%=email.getFirstChild().getNodeValue()%><br />
 
 Phone:<%=phone.getFirstChild().getNodeValue()%><br />
 
 <% NodeList n2 = order.getElementsByTagName( "credit_info" );
 
 Element credit = (Element)n2.item( 0 );
 
 Node number = credit.getElementsByTagName
( "card_number").item(0);
 
 Node type = credit.getElementsByTagName
( "card_type").item(0);
 
 Node exp = credit.getElementsByTagName
( "expiration_date").item(0);
 
 %>
 
 <h2>Credit Card Information</h2>
 
 Type:<%=type.getFirstChild().getNodeValue()%><br />
 
 Number:<%=number.getFirstChild().getNodeValue()%><br />
 
 Expiration Date:<%=exp.getFirstChild().getNodeValue()%><br />
 
 <% NodeList n3 = order.getElementsByTagName
( "authorization" );
 
 Element auth = (Element)n3.item( 0 );
 
 String approved = auth.getAttribute( "approved");
 
 Node reason = auth.getElementsByTagName
( "reason").item(0);
 
 Node auth_code = auth.getElementsByTagName
( "authorization_code").item(0);
 
 %>
 
 <h2>Authorization Information</h2>
 
 Auth Code:<%=auth_code.getFirstChild().getNodeValue()%>

<br />
 
 Approved:<%=approved%><br />
 
 Reason:<%=reason.getFirstChild().getNodeValue()%><br />
 
 <% NodeList n4 = order.getElementsByTagName( "fulfillment" );
 
 Element fulfillment = (Element)n4.item(0);
 
 Node shipper = fulfillment.getElementsByTagName
( "shipper" ).item(0);
 
 Node clas = fulfillment.getElementsByTagName( "class" ).item(0);
 
 Node cost = fulfillment.getElementsByTagName( "cost" ).item(0);
 
 Node tracking = fulfillment.getElementsByTagName
( "tracking_number" ).item(0);
 
 Node dateSent = fulfillment.getElementsByTagName
( "date_sent" ).item(0);
 
 String trackingString = tracking.getFirstChild().getNodeValue();
 
 String dateSentString = dateSent.getFirstChild().getNodeValue();
 
 %>

В нижней части этой JSP-страницы располагается форма, предназначенная для ввода номера отслеживания заказа и даты его отправки. Эти значения можно вводить в том случае, если в поле для номера указано значение NO_TRA- CKING_NUMBER (номер отсутствует). Эта строка используется для указания, что данное поле еще не инициализировано, так что пользователь может ввести новое значение. Если же значения уже заданы, они просто отобразятся и пользователь уже не сможет их редактировать. В этой форме (листинг 5.31) также имеется некоторое количество скрытых полей, которые содержат информацию, необходимую для JSP-страницы, обновляющей файл XML.

Листинг 5.31. Форма для ввода данных о доставке (ShowOrder.jsp)

<form action="UpdateFulfillment.jsp">
 
 <input type="hidden" name="dir" value="<%=dir%>" />
 
 <input type="hidden" name="file" value="<%=file%>" />
 
 <input type="hidden" name="email"
 
 value="<%=email.getFirstChild().getNodeValue()%>" />
 
 <input type="hidden" name="id" value="<%=id%>" />
 
 <input type="hidden" name="auth_code"
 
 value="<%=auth_code.getFirstChild().getNodeValue()%>" />
 
 <input type="hidden" name="price" value="<%=price%>" />
 
 <h2>Fulfillment Info</h2>
 
 Shipper:<%=shipper.getFirstChild().getNodeValue()%><br />
 
 Class:<%=clas.getFirstChild().getNodeValue()%><br />
 
 Cost:$<%=cost.getFirstChild().getNodeValue()%><br />
 
 Tracking #:
 
 <%if( trackingString.equals( "NO_TRACKING_NUMBER" ) ) { %>
 
 <input name="tracking" value="<%=trackingString%>" />
 
 Date Sent:<input name="date_sent" 
value="<%=dateSentString%>" />
 
 <input type="submit" value="Submit New Fulfillment Data" />
 
 <%} else {%>
 
 <%=trackingString%><br />
 
 Date Sent:<%=dateSentString%>
 
 <%}%>
 
 </form>
 
 <br /><a href="OrderDateSelector.jsp">
Back to date selection</a>
 
 </body>
 
 </html>

 

JSP-страница UpdateFullfilment

Последняя 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.

Листинг 5.32. JSP-страница UpdateFullfilment (UpdateFullfilment.jsp)

<%@ page import="java.io.*,com.XmlEcomBook.Chap05.*" %>
 
 <html>
 
 <head><title>Update Complete</title></head>
 
 <body>
 
 <% String tracking = request.getParameter( "tracking" );
 
 String dateSent = request.getParameter( "date_sent" );
 
 String dir = request.getParameter( "dir" );
 
 String filename = request.getParameter( "file" );
 
 String email = request.getParameter( "email" );
 
 String id = request.getParameter( "id" );
 
 String auth_code = request.getParameter( "auth_code" );
 
 String priceString = request.getParameter( "price" );
 
 double price = Double.parseDouble( priceString );
 
 File inFile = new File( dir, filename );
 
 File outFile = new File( dir, filename + ".tmp" );
 
 BufferedReader reader = new BufferedReader
( new FileReader( inFile ) );
 
 FileWriter writer = new FileWriter( outFile );
 
 String line;
 
 while( (line = reader.readLine()) != null ) {
 
 String newLine = replace( line, "NOT_SENT_YET", dateSent );
 
 newLine = replace( newLine, "NO_TRACKING_NUMBER", 
tracking );
 
 writer.write( newLine + "\n" );
 
 }
 
 reader.close();
 
 writer.close();
 
 inFile.renameTo( new File( dir, filename + ".old" ) );
 
 outFile.renameTo( inFile );
 
 Emailer.sendShipped( email, id );
 
 TestPaymentAuthorizer.capture( auth_code, price );
 
 %>
 
 <p>The fulfillment was updated with the new information.</p>
 
 <a href="OrderDateSelector.jsp">Back to date selection</a>
 
 </body>
 
 </html>
 
 <%!
 
 String replace( String s, String oldString, String newString ) {
 
 int pos = s.indexOf( oldString );
 
 String newLine = s;
 
 if( pos != -1 ) {
 
 newLine = s.substring( 0, pos );
 
 newLine += newString;
 
 newLine += s.substring( pos + oldString.length() );
 
 }
 
 return newLine;
 
 }
 
 %>

Листинги программ, приведенные в этой главе, показывают, как можно реализовать необходимые для работы магазина функции по обработке заказов и составлению счетов. Чтобы использовать эти программы в реальном магазине, необходима некоторая доработка. Наибольшие изменения будут касаться требований безопасности. JSP-страницы, которые задействуются в процессе ввода информации клиентом, должны использовать не простой протокол HTTP, a HTTPS. Далее, в нашем примере информация о клиентах хранилась в незашифрованном файле в той же системе файлов, в которой работает web-сервер магазина. В идеале вся персональная информация о клиентах должна храниться в зашифрованном, безопасном источнике данных на изолированном сервере, к которому нет доступа из Интернета.

С другой стороны, необходимо заменить класс, отвечающий за проверку номеров кредитных карт, на класс, который будет взаимодействовать с реальным поставщиком услуг по обработке. Но в процессе тестирования системы, на том этапе, когда еще не нужно взаимодействие с реальным поставщиком, можно воспользоваться приведенным здесь классом.

к библиотеке   к оглавлению   Банки данных Интернет   визуальные среды - 4GL   технологии программирования

Знаете ли Вы, почему "черные дыры" - фикция?
Согласно релятивистской мифологии, "чёрная дыра - это область в пространстве-времени, гравитационное притяжение которой настолько велико, что покинуть её не могут даже объекты, движущиеся со скоростью света (в том числе и кванты самого света). Граница этой области называется горизонтом событий, а её характерный размер - гравитационным радиусом. В простейшем случае сферически симметричной чёрной дыры он равен радиусу Шварцшильда".
На самом деле миф о черных дырах есть порождение мифа о фотоне - пушечном ядре. Этот миф родился еще в античные времена. Математическое развитие он получил в трудах Исаака Ньютона в виде корпускулярной теории света. Корпускуле света приписывалась масса. Из этого следовало, что при высоких ускорениях свободного падения возможен поворот траектории луча света вспять, по параболе, как это происходит с пушечным ядром в гравитационном поле Земли.
Отсюда родились сказки о "радиусе Шварцшильда", "черных дырах Хокинга" и прочих безудержных фантазиях пропагандистов релятивизма.
Впрочем, эти сказки несколько древнее. В 1795 году математик Пьер Симон Лаплас писал:
"Если бы диаметр светящейся звезды с той же плотностью, что и Земля, в 250 раз превосходил бы диаметр Солнца, то вследствие притяжения звезды ни один из испущенных ею лучей не смог бы дойти до нас; следовательно, не исключено, что самые большие из светящихся тел по этой причине являются невидимыми." [цитата по Брагинский В.Б., Полнарёв А. Г. Удивительная гравитация. - М., Наука, 1985]
Однако, как выяснилось в 20-м веке, фотон не обладает массой и не может взаимодействовать с гравитационным полем как весомое вещество. Фотон - это квантованная электромагнитная волна, то есть даже не объект, а процесс. А процессы не могут иметь веса, так как они не являются вещественными объектами. Это всего-лишь движение некоторой среды. (сравните с аналогами: движение воды, движение воздуха, колебания почвы). Подробнее читайте в FAQ по эфирной физике.

НОВОСТИ ФОРУМА

Форум Рыцари теории эфира


Рыцари теории эфира
 10.11.2021 - 12:37: ПЕРСОНАЛИИ - Personalias -> WHO IS WHO - КТО ЕСТЬ КТО - Карим_Хайдаров.
10.11.2021 - 12:36: СОВЕСТЬ - Conscience -> РАСЧЕЛОВЕЧИВАНИЕ ЧЕЛОВЕКА. КОМУ ЭТО НАДО? - Карим_Хайдаров.
10.11.2021 - 12:36: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от д.м.н. Александра Алексеевича Редько - Карим_Хайдаров.
10.11.2021 - 12:35: ЭКОЛОГИЯ - Ecology -> Биологическая безопасность населения - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> Проблема государственного терроризма - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> ПРАВОСУДИЯ.НЕТ - Карим_Хайдаров.
10.11.2021 - 12:34: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вадима Глогера, США - Карим_Хайдаров.
10.11.2021 - 09:18: НОВЫЕ ТЕХНОЛОГИИ - New Technologies -> Волновая генетика Петра Гаряева, 5G-контроль и управление - Карим_Хайдаров.
10.11.2021 - 09:18: ЭКОЛОГИЯ - Ecology -> ЭКОЛОГИЯ ДЛЯ ВСЕХ - Карим_Хайдаров.
10.11.2021 - 09:16: ЭКОЛОГИЯ - Ecology -> ПРОБЛЕМЫ МЕДИЦИНЫ - Карим_Хайдаров.
10.11.2021 - 09:15: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Екатерины Коваленко - Карим_Хайдаров.
10.11.2021 - 09:13: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вильгельма Варкентина - Карим_Хайдаров.
Bourabai Research - Технологии XXI века Bourabai Research Institution