■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2008年03月30日

    楽しいJava講座 - 初心者から達人へのパスポート
                  vol.097

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


[このメールマガジンは、画面を最大化して見てください。]


========================================================
◆ 01.Tomcatのアプリケーション開発
========================================================


前回、前提条件を追記したりしているので、念のために、
(操作1)から(操作5)までの内容を下記に提示し直しておきます。

--------------------------------------------------------
(操作1) 商品の検索および検索結果の表示
----------------------------------
■入力ページ:
・[itemSelectページ]
■前提条件:
・[itemSelectページ]においてキーワードが入力されていること(オプション)
・[itemSelectページ]においてカテゴリーが入力されていること(オプション)
・[itemSelectページ]において「送信」ボタンをクリックすること。
■事後条件:
■結果ページ:
・[itemListページ]
----------------------------------
 [itemSelectページ]→ ItemServlet.java → itemList.jsp
----------------------------------

(操作2) 商品をショッピング・カートに入れる
----------------------------------
■入力ページ:
・[itemListページ]
■前提条件:
・[itemListページ]において商品が選択されていること(オプション)
・[itemListページ]において「選択した商品をカートに入れる」ボタンを
クリックすること。
・セッション・オブジェクトの中にカートのオブジェクト
が入っていること(オプション)
■事後条件:
・セッション・オブジェクトの中にカートのオブジェクト
が入っていること。
■結果ページ:
・[cartページ]
----------------------------------
 [itemListページ]→ OrderItemServlet.java → cart.jsp
----------------------------------

(操作3) 購入個数の変更
----------------------------------
■入力ページ:
・[cartページ]
■前提条件:
・[cartページ]において商品の購入個数が変更されていること(オプション)
・[cartページ]において「選択した商品を購入する」ボタンをクリック
すること。
・セッション・オブジェクトの中にカートのオブジェクト
が入っていること。
<<条件が満たされていない場合→エラー・メッセージ:cartmissing.html>>
・購入対象の商品 = 購入個数の変更対象になる商品(OrderItem)オブジェクトが
既にカートのオブジェクトの中に入っていること。
また、カートのオブジェクトの中に商品(OrderItem)オブジェクトが
が入っていること(カートが空でないこと)。
<<条件が満たされていない場合→エラー・メッセージ:orderiteminvalid.html>>
■事後条件:
・セッション・オブジェクトの中にカートのオブジェクト
が入っていること。
■結果ページ:
・[orderページ]
----------------------------------
 [cartページ]→ OrderProcessServlet.java → order.jsp
----------------------------------

(操作4) ユーザーIDに対応した住所・氏名の取り出し
----------------------------------
■入力ページ:
・[orderページ]
■前提条件:
・[orderページ]において正しいユーザーIDが入力されていること
<<条件が満たされていない場合→エラー・メッセージ:wrongUser.jsp>>
・[orderページ]において正しいパスワードが入力されていること
 (本来は必須だが、今のところオプションとしておく)
・[orderページ]において「最終購入確認画面に進む」ボタンをクリック
すること。
・セッション・オブジェクトの中にカートのオブジェクト
が入っていること。
<<条件が満たされていない場合→エラー・メッセージ:ordermissing.html>>
・カートのオブジェクトの中に商品(OrderItem)オブジェクトが
が入っていること。
<<条件が満たされていない場合→エラー・メッセージ:invalidorder.html>>
■事後条件:
・Customerオブジェクトがセッション・オブジェクトの中にはいっていること。
■結果ページ:
・[confirmOrderページ]:商品の発送先(= ユーザーの住所・氏名)が表示され、
購入(注文)を確定するかどうか聞いてくる。
----------------------------------
 [orderページ]→ ConfirmOrderServlet.java → confirmOrder.jsp
----------------------------------

(操作5) 購入の確定(注文をデータベースへ登録)
----------------------------------
■入力ページ:
・[confirmOrderページ]
■前提条件:
・[confirmOrderページ]において、「購入(注文確定)する」ボタンをクリック
すること。
・セッション・オブジェクトの中にカートのオブジェクトが入っていること。
<<条件が満たされていない場合→エラー・メッセージ:ordermissing.html>>
・カートのオブジェクトの中に商品(OrderItem)オブジェクトが
が入っていること。
<<条件が満たされていない場合→エラー・メッセージ:invalidorder.html>>
・セッション・オブジェクトの中にCustomerオブジェクト
が入っていること。
<<条件が満たされていない場合→エラー・メッセージ:customermissing.html>>
■事後条件:
・セッション・オブジェクトが無効化されること。
■結果ページ:
・[completeOrderページ]
----------------------------------
 [confirmOrderページ]→ CompleteOrderServlet.java → completeOrder.jsp
--------------------------------------------------------



ところで、前回の最後に作成したinvalidorder.htmlは、いったい
どんなときにに表示されるのか、と疑問に思いませんでしたか?

「(操作3)の段階でカートが空だったらエラーになって次に進まないから
(操作4)の段階でカートが空になることはないのではないか。だったら
invalidorder.htmlが表示されることはないのではないか。」と思った人
もいるようですね。

はい。では、invalidorder.htmlを表示させるためのテスト方法を
以下に書いておきます。


まずEclipseでTomcatを起動し、Webブラウザーを起動して、下記のURLを
入力してください。

http://localhost:8080/JStudy2/itemSelect.html

(1) 「キーワード」欄、「カテゴリー」欄ともに何も入力せずに
「送信」ボタンをクリックしてみてください。

(2) 次のページ(商品リストのページ)で商品をどれか(たとえば「製品001」)
選択(チェック・マークを入れる)し、「選択した商品をカートに入れる」
ボタンをクリックします。

(3) 選択した商品が次のページ(ショッピング・カートのページ)で
リストされていることを確認し、「選択した商品を購入する」ボタンを
クリックします。

(4) 次のページ(購入手続きのページ)で、ユーザーIDには
J0001
などCUSTOMERテーブル上に存在する顧客番号を入力し、パスワードには
tekitou
など適当な値を入力して(あるいは入力しなくてもよい)
「最終購入確認画面に進む」ボタンをクリックします。

(5) 次のページで「購入(注文確定)する」ボタンをクリックします。

(6) 次のページで「商品の検索ページに戻るには、ここをクリック」をクリック
して、商品の検索ページへ進みます。

(7) 「キーワード」欄、「カテゴリー」欄ともに何も入力せずに
「送信」ボタンをクリックしてみてください。

(8) 次のページ(商品リストのページ)では商品をどれも選択せずに
「選択した商品をカートに入れる」ボタンをクリックします。

(9) 次のページ(ショッピング・カートの中のリスト)に商品が何もリスト
されていないことを確認し、Webブラウザーの「戻る」ボタンを何回かクリッ
クして、ユーザーIDとパスワードを入力するページまで戻ってください。

(10) ユーザーIDには
J0001
などCUSTOMERテーブル上に存在する顧客番号を入力し(前に入力したものが残って
いるはずなので、そのまま使えるはず)、パスワードには
tekitou
など適当な値を入力して(あるいは入力しなくてもよい)
「最終購入確認画面に進む」ボタンをクリックします。

(11) すると、「購入手続き不可」のページが表示され、
--------------------------------------------------------
ショッピング・カートの中に商品が入っていないなどの理由により、購入手続きを進めることができません。
まことに申し訳ありませんが、商品の検索から再度やり直してください。 
--------------------------------------------------------
というメッセージが表示されますね。

これはinvalidorder.htmlのWebページですね。


というわけで、一見、この前提条件がはずれることはありえないんじゃないの、
と思われるような場合でも、前提条件が満たされない場合の処理をちゃんと実装し
ておくべきなのです。



さて、前提条件が満たされていないときの対処のプログラミング
の続きですが、前回は(操作4)までのプログラミングが終わりましたので、
今日は(操作5)です。


では、(操作5)の前提条件を確認しましょう。

まず、
--------------------------------------------------------
・セッション・オブジェクトの中にカートのオブジェクトが入っていること。
<<条件が満たされていない場合→エラー・メッセージ:ordermissing.html>>
--------------------------------------------------------
の部分は既に実装済みですね。

次に
--------------------------------------------------------
・カートのオブジェクトの中に商品(OrderItem)オブジェクトが
が入っていること。
<<条件が満たされていない場合→エラー・メッセージ:invalidorder.html>>
・セッション・オブジェクトの中にCustomerオブジェクト
が入っていること。
<<条件が満たされていない場合→エラー・メッセージ:customermissing.html>>
--------------------------------------------------------
の部分を実装しましょう。

CompleteOrderServletを下記のように編集してください。
--------------------------------------------------------
package jp.co.flsi.lecture.webapp.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import jp.co.flsi.lecture.webapp.db.OrderDbManager;
import jp.co.flsi.lecture.webapp.entity.Customer;
import jp.co.flsi.lecture.webapp.entity.Order;

public class CompleteOrderServlet extends HttpServlet {
   public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
      req.setCharacterEncoding("Shift_JIS");
      HttpSession session = req.getSession();
      Order anOrder = (Order)session.getAttribute("ORDER");
      Customer aCustomer = (Customer)session.getAttribute("CUSTOMER");
      if (anOrder == null) {
         getServletContext().getRequestDispatcher("/ordermissing.html").forward(req,res);
      }
      else if (aCustomer == null) {
         getServletContext().getRequestDispatcher("/customermissing.html").forward(req,res);
      }
      else if (anOrder.getOrderItems().size() < 1) {
         getServletContext().getRequestDispatcher("/invalidorder.html").forward(req,res);
      }
      else {
         anOrder.setCustomerNum(aCustomer.getNum());
         OrderDbManager orderDb = new OrderDbManager();
         orderDb.insertData(anOrder);
         getServletContext().getRequestDispatcher("/completeOrder.jsp").forward(req,res);
      }
   }

   public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
      getServletContext().getRequestDispatcher("/bookmarkinvalid.html").forward(req,res);
   }

}
--------------------------------------------------------


続いて下記のようなcustomermissing.htmlを作成しましょう。
(例によってitemSelect.htmlと同じ場所、つまりJStudy2の直下
に作成してください。)
--------------------------------------------------------
<HTML>
<HEAD>
<TITLE>購入者情報エラー</TITLE>
</HEAD>
<BODY bgcolor="#77ffff" text="#fa5a00">
<H1>購入者情報エラー</H1>
購入者情報が存在しないか、または消失しています。
<BR>
まことに申し訳ありませんが、商品の検索から再度やり直してください。
<BR>
<BR>
<A href="http://localhost:8080/JStudy2/itemSelect.html">
商品の検索に戻るには、ここをクリック
</A>
<BR>
</BODY>
</HTML>
--------------------------------------------------------



ところで、これまで購入者(= 顧客 = ユーザー)の情報は予めデータベース
に入力しておいたものを使っており、ユーザー登録のページ(ユーザーが自分
の住所・氏名の情報を登録するためのWebページ)はまだ用意していませんで
した。

当アプリケーションは、注文時に顧客のユーザーIDの入力を必要としていますから、
ユーザー登録のページが用意されていなければアプリケーションとしては不完全です。

というわけで、これからユーザー登録の機能を作っていきましょう。

なお、ユーザー登録のページは注文時だけでなく、別の時点でも呼び出せるもの
とします。


では、まず最初に、ユーザーの情報をCUSTOMERテーブルに登録するための
メソッドを、CustomerDbManagerに組み込みましょう。

CustomerDbManagerクラスを下記のように編集してみて下さい。
--------------------------------------------------------
package jp.co.flsi.lecture.webapp.db;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;

import jp.co.flsi.lecture.webapp.entity.Customer;

public class CustomerDbManager extends DbManager {
   private Vector<Customer> customerList = new Vector<Customer>();
   private String selectAllSql = "SELECT * FROM CUSTOMER";
   private String selectNumSql = "SELECT * FROM CUSTOMER WHERE NUM = ?";
   private String insertSql = "INSERT INTO CUSTOMER  VALUES (?, ?, ?, ?)";

   public Vector<Customer> getCustomerList() {
      return customerList;
   }

   public void selectAllData() {
      try {
         connect();
         Statement selectSql = conn.createStatement();
         ResultSet rs = selectSql.executeQuery(selectAllSql);
         while (rs.next()) {
            Customer aCustomer = new Customer();
            aCustomer.setNum(rs.getString("NUM"));
            aCustomer.setName(rs.getString("NAME"));
            aCustomer.setZipCode(rs.getString("ZIPCODE"));
            aCustomer.setAddress(rs.getString("ADDRESS"));
            getCustomerList().addElement(aCustomer);
         }
         selectSql.close();
         disconnect();
      }
      catch (SQLException exception) {
         exception.printStackTrace();
      }
   }

   public void selectData(String customerNum) {
      try {
         connect();
         PreparedStatement selectPs = null;
         ResultSet rs;
         if (customerNum == null) {
            selectPs = conn.prepareStatement(selectAllSql);
            rs = selectPs.executeQuery(selectAllSql);
         }
         else {
            selectPs = conn.prepareStatement(selectNumSql);
            selectPs.setString(1, customerNum);
            rs = selectPs.executeQuery();
         }
         while (rs.next()) {
            Customer aCustomer = new Customer();
            aCustomer.setNum(rs.getString("NUM"));
            aCustomer.setName(rs.getString("NAME"));
            aCustomer.setZipCode(rs.getString("ZIPCODE"));
            aCustomer.setAddress(rs.getString("ADDRESS"));
            getCustomerList().addElement(aCustomer);
         }
         selectPs.close();
         disconnect();
      }
      catch (SQLException exception) {
         exception.printStackTrace();
      }
   }
  
   public void insertData(Customer aCustomer) {
      try {
         connect();
         PreparedStatement insertPs = conn.prepareStatement(insertSql);
         insertPs.setString(1, aCustomer.getNum());
         insertPs.setString(2, aCustomer.getName());
         insertPs.setString(3, aCustomer.getZipCode());
         insertPs.setString(4, aCustomer.getAddress());
         insertPs.executeUpdate();
         insertPs.close();
         conn.commit();
         disconnect();
      }
      catch (SQLException exception) {
         exception.printStackTrace();
      }
      catch (Exception otherException) {
         otherException.printStackTrace();
      }
   }

}
--------------------------------------------------------

以前のソース・コードと違うところはinsertData()というメソッドとINSERTのSQL文が
追加されたことだけですね。
このソース・コードも、いつものパターンなので、解説しなくても理解できますね。



続いてユーザー登録のWebページを作りましょう。


(次回に続く)


では、今日はここまでにします。

何か、わからないところがありましたら、下記のWebページまで質問を
お寄せください。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2008 Future Lifestyle Inc. 不許無断複製