■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2008年01月20日

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

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


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


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

さて、いよいよ今回から注文の機能のプログラミングにはいって
いきたいと思いますが、その前に、思慮深い人は、前回のコーディ
ング内容について、気になったことがあるでしょう。


前回のitemList.jspの内容を再度確認してみてください。
--------------------------------------------------------
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="Shift_JIS" %>

<HTML>
<HEAD>
<TITLE>商品リスト</TITLE>
</HEAD>
<BODY bgcolor="#77ffff" text="#fa5a00">
<H1>商品のリスト</H1>
<TABLE border="1" width="100%">
  <TBODY>
    <TR>
      <TH>商品番号</TH>
      <TH>商品名</TH>
      <TH>価格</TH>
      <TH>カテゴリー</TH>
      <TH>イメージ</TH>
    </TR>

<%@ page import="java.util.Vector" %>
<%@ page import="jp.co.flsi.lecture.webapp.entity.*" %>
<jsp:useBean class="jp.co.flsi.lecture.webapp.db.ItemDbManager" id="ITEMDB" scope="request" />
<%    Item  anItem;
      Vector<Item> itemList = ITEMDB.getItemList();
      for (int i = 0; i < itemList.size(); i++) {
         anItem = itemList.elementAt(i); %>
          <TR>
            <TD><%= anItem.getNum() %></TD>
            <TD><%= anItem.getName() %></TD>
            <TD><%= anItem.getPrice() %></TD>
            <TD><%= anItem.getCategory() %></TD>
            <TD><IMG src="http://localhost:8080/JStudy2<%= anItem.getImage() %>"></TD>
          </TR>
<%      } %>

  </TBODY>
</TABLE>

</BODY>
</HTML>
--------------------------------------------------------

このソース・コードの中の

<IMG src="http://localhost:8080/JStudy2

の部分で使っているlocalhostというのは自分のコンピューター
のことでしたね。
これでは、同一のパソコンからアクセスすることはできても、
ネットワークを隔てて接続された他のコンピューターから
アクセスすることができませんね。

というわけで、このソース・コードのままでは、本番運用のとき
には使えません。
では、localhostの代わりに本番運用時のサーバーのIPアドレス
(もしくはドメイン名)を指定すればいいのでしょうか?
通常は、本番運用時のサーバーと開発時に使うコンピューターは
別物ですから、これでは開発時に困ります。
では、開発時はlocalhostにしておいて本番運用のときに書き換え
ればいいではないか、と思うかもしれませんが、これもまた面倒
ですし、書き換え忘れたりする恐れがありますから好ましくあり
ません。


この問題に対する一つの対処法は、次のようなものです。(他にも
対処方法はあります。)

まず、

<%  StringBuffer sb = request.getRequestURL(); %>

というコードを入れてやると、変数sbにこのJSPのURLがはいります。
(StringBufferというクラスは、Stringによく似たクラスで文字列
を表現しますが、保有する文字列の値が可変である、つまり文字列
の値を変えることができるという点でStringと異なります。ただし、
今回はStringと同様の使い方しかしませんので、細かいことは気に
しなくていいです。
また、JSPの中のrequestという変数が、サーブレットが受け取った
HttpServletRequestオブジェクトを表すことは、vol.076でお話した
通りです。)

このURLは、WebブラウザーがこのJSPを呼び出したとき(要求した時)
のURLです。
(正確にいうと、実際にはWebブラウザーからはサーブレットを呼び
出しているので、Webブラウザーからの要求時のURLはサーブレットの
URLなんですが、サーブレットから

getServletContext().getRequestDispatcher("/itemList.jsp").forward(req,res);

のコードによって要求がJSPに転送されたときに、要求時のURLがJSPの
URLに書き換えられるようになっています。)

そして、このJSPのURLは

http://IPアドレス:8080/JStudy2/itemList.jsp

のような形になります。(上記の「IPアドレス」の部分には実際の
サーバーのIPアドレスまたはドメイン名がはいります。)
そこで、その後で

<%= sb.substring(0, sb.lastIndexOf("/")) %>

というコードを入れてやると、最後のスラッシュ(/)以下が取り除か
れた文字列、つまり

http://IPアドレス:8080/JStudy2

という部分が取り出せます。(上記のsubstring()メソッドは、vol.075
で出てきたものと同じものです。)

この仕組みを利用して、itemList.jspを下記のように書き換えて
みましょう。
--------------------------------------------------------
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="Shift_JIS" %>

<HTML>
<HEAD>
<TITLE>商品リスト</TITLE>
</HEAD>
<BODY bgcolor="#77ffff" text="#fa5a00">
<H1>商品のリスト</H1>
<TABLE border="1" width="100%">
  <TBODY>
    <TR>
      <TH>商品番号</TH>
      <TH>商品名</TH>
      <TH>価格</TH>
      <TH>カテゴリー</TH>
      <TH>イメージ</TH>
    </TR>

<%@ page import="java.util.Vector" %>
<%@ page import="jp.co.flsi.lecture.webapp.entity.*" %>
<jsp:useBean class="jp.co.flsi.lecture.webapp.db.ItemDbManager" id="ITEMDB" scope="request" />
<%    Item  anItem;
      Vector<Item> itemList = ITEMDB.getItemList();
      StringBuffer sb = request.getRequestURL();
      for (int i = 0; i < itemList.size(); i++) {
         anItem = itemList.elementAt(i); %>
          <TR>
            <TD><%= anItem.getNum() %></TD>
            <TD><%= anItem.getName() %></TD>
            <TD><%= anItem.getPrice() %></TD>
            <TD><%= anItem.getCategory() %></TD>
            <TD><IMG src="<%= sb.substring(0, sb.lastIndexOf("/")) %><%= anItem.getImage() %>"></TD>
          </TR>
<%      } %>

  </TBODY>
</TABLE>

</BODY>
</HTML>
--------------------------------------------------------

これなら、開発時でも本番運用時でもソース・コードの変更なしに
使えますね。


では、itemSelect.html
--------------------------------------------------------
<HTML>
<HEAD>
<TITLE>商品の検索</TITLE>
</HEAD>
<BODY bgcolor="#77ffff" text="#fa5a00">
<H1>商品の検索</H1>
<FORM action="http://localhost:8080/JStudy2/servlet/items" method="POST">
キーワード(商品名の一部)とカテゴリーを入力し、「送信」ボタンをクリックしてください。
<BR>
<BR>
キーワード:<INPUT TYPE="text" NAME="itemName" VALUE="" SIZE=20>
<BR>
カテゴリー:<INPUT TYPE="text" NAME="category" VALUE="" SIZE=20>
<BR>
<BR>
<INPUT TYPE="submit" NAME="sumit" VALUE="送信">
</FORM>
</BODY>
</HTML>
--------------------------------------------------------

のほうはどうでしょうか。
この中の

<FORM action="http://localhost:8080/JStudy2/servlet/items" method="POST">

の部分もlocalhostを含んでいますね。
でも、困ったことにHTMLはJSPではありませんから、Javaのプログラム
を組み込むことはできません。

でも、心配要りません。
itemSelect.htmlは

http://IPアドレス:8080/JStudy2/itemSelect.html

という形のURLによってWebブラウザーから呼び出された(要求された)
はずですから、WebブラウザーはitemSelect.htmlファイルの根元が
http://IPアドレス:8080/JStudy2/
であることを知っているのです。
そこで、

<FORM action="servlet/items" method="POST">

というふうに指定してやると、Webブラウザーが自動的にservlet/itemsの前に
http://IPアドレス:8080/JStudy2/
という根元の部分を補ってくれて
http://IPアドレス:8080/JStudy2/servlet/items
というURLでサーブレットを要求してくれることになっています。

この仕組みを利用して、itemSelect.htmlを
--------------------------------------------------------
<HTML>
<HEAD>
<TITLE>商品の検索</TITLE>
</HEAD>
<BODY bgcolor="#77ffff" text="#fa5a00">
<H1>商品の検索</H1>
<FORM action="servlet/items" method="POST">
キーワード(商品名の一部)とカテゴリーを入力し、「送信」ボタンをクリックしてください。
<BR>
<BR>
キーワード:<INPUT TYPE="text" NAME="itemName" VALUE="" SIZE=20>
<BR>
カテゴリー:<INPUT TYPE="text" NAME="category" VALUE="" SIZE=20>
<BR>
<BR>
<INPUT TYPE="submit" NAME="sumit" VALUE="送信">
</FORM>
</BODY>
</HTML>
--------------------------------------------------------

というふうに書き換えましょう。

これなら、開発時でも本番運用時でも変更なしに使えますね。




では、今度は、商品を注文(購入)するための機能をプログラミング
していきましょう。

まず、購入したい商品を一時的に入れておくためのショッピング・
カートのクラスを作りましょう。

現実のショッピング・カートは、車輪がついたカゴというイメージ
で認識されるかもしれませんが、今回のアプリケーション上では
そんなものは必要ありませんね。
たんに購入したい商品と購入したい個数の情報がはいっていれば
いいだけです。
そして、その情報はそのまま注文(購入)の段階でも使用できます。

そこで、アプリケーションを簡潔にするために、注文のクラス
(Orderという名前にする)をショッピング・カートとしても
使用することにし、ショッピング・カートか注文かの区別は、
注文が完了したかどうかの属性を持たせることによって示すこと
にします。
つまり、Orderオブジェクトの注文完了の属性が注文前を示して
いれば商品がショッピング・カートにはいっている状態を意味し、
注文完了を示していればショッピング・カートから商品が取り
出されてレジを通過し、商品が購入済み(注文済み)の状態になった
ことを意味することとします。

というわけで、注文とショッピング・カートを表現するクラスとして
Orderを作りますが、その前に、そのOrderオブジェクトの中に含ま
れる商品、つまり、ショッピング・カートにはいっている商品
あるいは注文が完了した商品を表現するクラスとして、OrderItem
というクラスを用意しましょう。商品を表すフィールド(属性の変数)
としては商品番号の変数(itemNumという名前にする)を用意し、
購入希望数を表すフィールドとしてはorderQuantityという名前の
変数を用意することにします。
また、注文書の中での商品項目の番号(何行目の項目であるかを表す番号)
をseqNumberという名前のフィールドで表すことにします。

Itemクラスを作成したときと同様にして下記のようなOrderItemクラス
を作成してください。
--------------------------------------------------------
package jp.co.flsi.lecture.webapp.entity;

public class OrderItem {
   private int seqNumber;
   private String itemNum;
   private int orderQuantity;

   public OrderItem() {
      setSeqNumber(0);      // 0は未設定を意味するものとする。
      setOrderQuantity(1);  // 注文個数のデフォルトは1とする。
   }
   public void setSeqNumber(int seqNumber) {
      this.seqNumber = seqNumber;
   }

   public int getSeqNumber() {
      return seqNumber;
   }

   public void setItemNum(String itemNum) {
      this.itemNum = itemNum;
   }

   public String getItemNum() {
      return itemNum;
   }

   public void setOrderQuantity(int orderQuantity) {
      this.orderQuantity = orderQuantity;
   }
  
   public int getOrderQuantity() {
      return orderQuantity;
   }

}
--------------------------------------------------------
このソース・コードは、とくに解説しなくても理解できますね。

これはORDERITEMテーブルをマッピングしたクラスですね。
ORDERITEMテーブルと照らし合わせてみてください。


続いて、同様にして下記のようなOrderクラスを作成してください。
--------------------------------------------------------
package jp.co.flsi.lecture.webapp.entity;

import java.util.Date;
import java.util.Vector;

public class Order {
   private int orderNumber;
   private String customerNum;
   private Date orderDate;
   private boolean payment;
   private short delivery;
   private Vector<OrderItem> orderItems;
   private boolean orderComplete;
  
   public Order() {
      setOrderNumber(0);        // 0は未設定を意味するものとする。
      setPayment(false);        // デフォルトは未払い。
      setDelivery((short)0);    // デフォルトは未配達。
      setOrderComplete(false);  // デフォルトは注文前
      orderItems = new Vector<OrderItem>();
   }
  
   public void setOrderNumber(int orderNumber) {
      this.orderNumber = orderNumber;
   }

   public int getOrderNumber() {
      return orderNumber;
   }
  
   public void setCustomerNum(String customerNum) {
      this.customerNum = customerNum;
   }

   public String getCustomerNum() {
      return customerNum;
   }
  
   public void setOrderDate(Date orderDate) {
      this.orderDate = orderDate;
   }
  
   public Date getOrderDate() {
      return orderDate;
   }
  
   public void setPayment(boolean payment) {
      this.payment = payment;
   }
  
   public boolean isPayment() {
      return payment;
   }
  
   public void setDelivery(short delivery) {
      this.delivery = delivery;
   }

   public short getDelivery() {
      return delivery;
   }

   public void setOrderItems(Vector<OrderItem> orderItems) {
      this.orderItems = orderItems;
   }
  
   public Vector<OrderItem> getOrderItems() {
      return orderItems;
   }

   public void addOrderItem(OrderItem anOrderItem) {
      this.orderItems.add(anOrderItem);
   }
  
   public void removeOrderItem(OrderItem anOrderItem) {
      for (int i = 0; i < this.orderItems.size(); i++) {
         if (this.orderItems.get(i).getItemNum().equals(anOrderItem.getItemNum())) {
            this.orderItems.remove(i);
         }
      }
   }
  
   public void setOrderComplete(boolean orderComplete) {
      this.orderComplete = orderComplete;
   }

   public boolean isOrderComplete() {
      return orderComplete;
   }

}
--------------------------------------------------------
ここで、orderNumberというフィールドは注文番号を表し、
customerNumというフィールドはは注文する顧客の顧客番号を表し、
orderDateというフィールドは注文日付を表します。
また、paymentは料金の支払いが終わっているかどうか、
deliveryは配達状況を表す変数です(値が0のときは未配達、
値が1のときは配達済み、値が2のときは配達中を意味するもの
とします)。
また、orderCompleteは注文が完了したか、あるいは注文前
(すなわちショッピング・カートにはいっている状態)であるか、
を表すフィールドです。値が偽のときは注文前、値が真のときは
注文完了後を表すものとします。

あとは説明しなくてもわかりますね。
このクラスはORDERHEADERテーブルをマッピングしています。



では、前回の商品検索のプログラムを使って取り出した商品リスト
の中から、購入したい商品を選択すると、その商品(正確にはその
商品の情報)がショッピング・カートに入るようにプログラミング
していきましょう。

まず、itemList.jspを少し書き換えます。
下記のように書き換えてください。

--------------------------------------------------------
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="Shift_JIS" %>

<HTML>
<HEAD>
<TITLE>商品リスト</TITLE>
</HEAD>
<BODY bgcolor="#77ffff" text="#fa5a00">
<H1>商品のリスト</H1>
<FORM action="orderitems" method="POST">
<TABLE border="1" width="100%">
  <TBODY>
    <TR>
      <TH>商品番号</TH>
      <TH>商品名</TH>
      <TH>価格</TH>
      <TH>カテゴリー</TH>
      <TH>イメージ</TH>
      <TH>選択</TH>
    </TR>

<%@ page import="java.util.Vector" %>
<%@ page import="jp.co.flsi.lecture.webapp.entity.*" %>
<jsp:useBean class="jp.co.flsi.lecture.webapp.db.ItemDbManager" id="ITEMDB" scope="request" />
<%      Item  anItem;
       Vector<Item> itemList = ITEMDB.getItemList();
       StringBuffer sb = request.getRequestURL();
      for (int i = 0; i < itemList.size(); i++) {
         anItem = itemList.elementAt(i); %>
          <TR>
            <TD><%= anItem.getNum() %></TD>
            <TD><%= anItem.getName() %></TD>
            <TD><%= anItem.getPrice() %>円</TD>
            <TD><%= anItem.getCategory() %></TD>
            <TD><IMG src="<%= sb.substring(0, sb.lastIndexOf("/")) %><%= anItem.getImage() %>"></TD>
            <TD><INPUT TYPE="checkbox" NAME="<%= anItem.getNum() %>"></TD>
          </TR>
<%      } %>

  </TBODY>
</TABLE>
<BR>
<BR>
<INPUT TYPE="submit" NAME="putIntoCart" VALUE="選択した商品をカートに入れる">
</FORM>
</BODY>
</HTML>
--------------------------------------------------------

このソース・コードの説明は次回行います。



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


(次回に続く)


何か、わからないところがありましたら、下記の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. 不許無断複製