■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2008年01月27日

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

                                セルゲイ・ランダウ
 バックナンバー: 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>
<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>
--------------------------------------------------------

まず最初に

<FORM action="orderitems" method="POST">

の行を見てください。
ここでも前回のitemSelect.htmlのときと同じように
省略された形のURLを使っています。

このJSPが返すWebページは、Webブラウザーからみれば、
前回のitemSelect.htmlによってサーブレットを呼び出した
ときに返ってくるページです。
つまり、

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

というURLによってサーブレットを呼び出し、その結果返ってくる
ページなので、この段階ではWebブラウザーは、その根元の

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

という部分を認識しています。

そこで、

<FORM action="orderitems" method="POST">

という指定をすると、

<FORM action="http://IPアドレス:8080/JStudy2/servlet/orderitems" method="POST">

という指定と同じ扱いにしてくれます。つまり、

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

というURLでサーブレットを呼び出してくれるのです。


次に、INPUTタグがフォームの入力情報を記述するためのタグ
であることは、既にvol.075で説明しましたが、そのうち

<INPUT TYPE="checkbox" NAME="<%= anItem.getNum() %>">

のようにTYPE属性の値に"checkbox"を指定するとWebページ上に
チェックボックスを表示してくれます。
そして、そのチェックボックスにチェックマークを入れる(クリック
するとチェックマークが入る)と、そのNAME属性の値がパラメーター
の名前としてサーブレットに渡されます。

そこで、どんなパラメーターの名前が渡されたかをサーブレットで
調べれば、どの商品にチェックマークが入れられたかがわかるの
です。

ここでは、NAME属性の値に

<%= anItem.getNum() %>

を指定することによって、パラメーターの名前として商品番号が
渡るようにしています。
したがって、サーブレットには、選択された(チェックマークが
入れられた)商品の商品番号がパラメーターの名前として渡される
ことになります。

これに対して

<INPUT TYPE="submit" NAME="putIntoCart" VALUE="選択した商品をカートに入れる">

という行にも注意してください。
このようにTYPE属性に"submit"という値を指定すると、送信を行う
ためのボタンを表示してくれることは、既にvol.075で説明した
通りです。
そして、そのボタンをクリックすると、フォームに入力されたデータ
がサーブレットに送り込まれるのでしたね。

このとき、先ほどの商品番号といっしょにこのボタンのNAME属性の
値(ここでは"putIntoCart"という値にしている)もパラメーターの
名前としてサーブレットに渡されてしまうので、注意してください。
サーブレットの中で商品番号と"putIntoCart"という値を明確に区別
しておく必要があります。(あとでサーブレットの解説をするときに
再度説明します。)

そして、この"putIntoCart"ボタンをクリックすると商品がショッピン
グ・カートに入れられるということにして、ショッピング・カートの
中にはいった商品のリストを表示するWebページに進むことにします。

ところで、ショッピング・カートの中の商品を表現するクラスは
OrderItemクラスですが、OrderItemクラスには商品名や画像の属性
がありませんでしたね。ショッピング・カートの中の商品の情報と
して商品番号だけリストしたのでは貧相ですから、OrderItemクラス
にも商品名や画像の属性を持たせるように変更しましょう。
この変更はOrderItemをItemのサブクラスにしてしまえば簡単です。
ただし、商品番号がnumとitemNumという2つの重複したフィールドに
よって表現されることになってしまうのでitemNumのほうは削除します。

というわけで、OrderItemクラスを下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.webapp.entity;

public class OrderItem extends Item {
   private int seqNumber;
   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 setOrderQuantity(int orderQuantity) {
      this.orderQuantity = orderQuantity;
   }
  
   public int getOrderQuantity() {
      return orderQuantity;
   }

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

そうすると、OrderクラスでもgetItemNum()メソッドを呼び出して
いるところがエラー(赤色のマークがつく)になりますね。
したがって、そこをgetNum()に書き換える必要があることがわかり
ます。
そこを修正することによって、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).getNum().equals(anOrderItem.getNum())) {
            this.orderItems.remove(i);
         }
      }
   }
  
   public void setOrderComplete(boolean orderComplete) {
      this.orderComplete = orderComplete;
   }

   public boolean isOrderComplete() {
      return orderComplete;
   }

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



続いて次のようなサーブレット(OrderItemServlet)を作り
ましょう。
--------------------------------------------------------
package jp.co.flsi.lecture.webapp.servlet;

import java.io.IOException;
import java.util.Enumeration;

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

import jp.co.flsi.lecture.webapp.db.ItemDbManager;
import jp.co.flsi.lecture.webapp.entity.Order;
import jp.co.flsi.lecture.webapp.entity.OrderItem;
import jp.co.flsi.lecture.webapp.entity.Item;

public class OrderItemServlet extends HttpServlet {
   public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
      req.setCharacterEncoding("Shift_JIS");
      Order anOrder = new Order();
      ItemDbManager itemDb = new ItemDbManager();
      itemDb.selectAllData();
      Enumeration paramNames = req.getParameterNames();
      while(paramNames.hasMoreElements()) {
         String aParamName = (String)paramNames.nextElement();
         if (!aParamName.equals("putIntoCart")) {
            OrderItem anOrderItem = new OrderItem();
            for (Item anItem : itemDb.getItemList()) {
               if(aParamName.equals(anItem.getNum())) {
                  anOrderItem.setNum(anItem.getNum());
                  anOrderItem.setName(anItem.getName());
                  anOrderItem.setPrice(anItem.getPrice());
                  anOrderItem.setImage(anItem.getImage());
                  anOrderItem.setCategory(anItem.getCategory());
               }
            }
            anOrder.addOrderItem(anOrderItem);
         }
      }
      req.setAttribute("ORDER",anOrder);
      getServletContext().getRequestDispatcher("/cart.jsp").forward(req,res);
   }

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

ここで、

Enumeration paramNames = req.getParameterNames();

のgetParameterNames()メソッドは初めて出てきましたが、これが
パラメーターの名前を取り出すためのメソッドです。

通常、パラメーターは複数個取り出されるので、Enumerationという
型の戻り値にすることによって複数個処理できるようにしています。

Enumerationというのは、Vectorなどのように何らかのオブジェクト
を複数個入れる入れ物のようなオブジェクトに対し、その入れ物に
はいっているオブジェクト(入れ物の中にはいっているオブジェクト
を要素(element)と呼ぶ)を先頭から順番に一つずつ取り出す操作
(メソッド)を規定したインターフェースで、nextElement()という、
次の要素を取り出すメソッドと、hasMoreElements()という、その後ろ
にまだ要素が残っているかどうかを調べるメソッドの2つのメソッド
が用意されています。

つまりEnumeration型のオブジェクトはVectorか何かの入れ物的な
オブジェクトを保持しており、その入れ物の中の要素は、nextElement()
とhasMoreElements()という2つのメソッドを使って順番に取り出していく
というルールになっているのです。

現在ではEnumeration<E>という形式で型を指定することによって、
Eの部分に要素の型を明示できるようになっており、明示することに
よってあいまいさがなくなり、型の扱い対する安全性が向上する
というメリットがあります。


上のgetParameterNames()メソッドの戻り値は、ただのEnumeration型
になっており、要素の型は明示されていませんが、実際にはパラメーター
の名前を要素として保有しており、パラメーターの名前はString型です。
したがって、

String aParamName = (String)paramNames.nextElement();

の行では、nextElement()メソッドの戻り値をString型にキャスト
してString型の変数(ここではaParamNameという変数名)に代入
しています。

一方、

while(paramNames.hasMoreElements()) {

の行ではhasMoreElements()メソッドによって、まだ要素が残っている
かどうかを確認(hasMoreElements()メソッドは、要素が残っていれば
trueを、残っていなければfalseを返す)しています。
つまり、その下の行のnextElement()メソッド呼び出しとの組み合わせ
によって、先頭から一つずつ要素を取り出し、要素がなくなるまで繰り
返すということを行っているわけですが、これがEnumeration型のオブ
ジェクトの標準的な処理方法です。

それから次に、その下の

if (!aParamName.equals("putIntoCart")) {

という行に注目してください。
これは、先ほどのJSPの説明のときにお話した"putIntoCart"という値
を商品番号と区別して除外するためのコードです。
"putIntoCart"さえ除外すれば、あとのパラメーターの名前は商品番号
だけになりますね。


このサーブレットの残りのソース・コードは説明しなくても理解でき
ますね。なお、cart.jspというのはあとで作ります。



では続いて、このサーブレットをweb.xmlに登録すべく、web.xmlを
次のように編集しましょう。
--------------------------------------------------------
<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>jp.flsi.lecture.servlet.TestServlet</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>TestServlet2</servlet-name>
        <servlet-class>jp.flsi.lecture.servlet.TestServlet2</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>AgeCalcServlet</servlet-name>
        <servlet-class>jp.co.flsi.lecture.webapp.servlet.AgeCalcServlet</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>CustomerServlet</servlet-name>
        <servlet-class>jp.co.flsi.lecture.webapp.servlet.CustomerServlet</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>ItemServlet</servlet-name>
        <servlet-class>jp.co.flsi.lecture.webapp.servlet.ItemServlet</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>OrderItemServlet</servlet-name>
        <servlet-class>jp.co.flsi.lecture.webapp.servlet.OrderItemServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/servlet/test</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>TestServlet2</servlet-name>
        <url-pattern>/servlet/test2</url-pattern>
    </servlet-mapping>
   
    <servlet-mapping>
        <servlet-name>AgeCalcServlet</servlet-name>
        <url-pattern>/servlet/age</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>CustomerServlet</servlet-name>
        <url-pattern>/servlet/customers</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>ItemServlet</servlet-name>
        <url-pattern>/servlet/items</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>OrderItemServlet</servlet-name>
        <url-pattern>/servlet/orderitems</url-pattern>
    </servlet-mapping>
   
</web-app>
--------------------------------------------------------

<url-pattern>に/servlet/orderitemsが指定されていることに
注意してください。
この指定によって、

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

という形式のURL(ただし「IPアドレス」の部分には実際の
IPアドレスか、ドメイン名がはいる)によって、サーブレット

jp.co.flsi.lecture.webapp.servlet.OrderItemServlet

が呼び出されることになります。



では今度は、さきほど作ったサーブレットから呼び出される
ことになっているcart.jspを作りましょう。
選択された(チェックボックスにチェックマークが入れられた)
商品はショッピング・カートに入れられたというイメージになる
ので、そのショッピング・カートに入っている商品を表示するために
この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="orderprocess" 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.entity.Order" id="ORDER" scope="request" />
<%    OrderItem anOrderItem;
      StringBuffer sb = request.getRequestURL();
      for (int i = ORDER.getOrderItems().size() - 1; i >= 0 ; i--) {
         anOrderItem = ORDER.getOrderItems().elementAt(i); %>
         <TR>
            <TD><%= anOrderItem.getNum() %></TD>
            <TD><%= anOrderItem.getName() %></TD>
            <TD><%= anOrderItem.getPrice() %>円</TD>
            <TD><%= anOrderItem.getCategory() %></TD>
            <TD><IMG src="<%= sb.substring(0, sb.lastIndexOf("/")) %><%= anOrderItem.getImage() %>"></TD>
            <TD><INPUT TYPE="text" NAME="<%= anOrderItem.getNum() + "_quantity" %>"
                                   VALUE="<%= anOrderItem.getOrderQuantity() %>" SIZE=1></TD>
          </TR>
<%    } %>

  </TBODY>
</TABLE>
<BR>
<BR>
<INPUT TYPE="submit" NAME="putIntoOrder" VALUE="選択した商品を購入する">
</FORM>
</BODY>
</HTML>
--------------------------------------------------------

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


では、EclipseでTomcatを起動し、テストしてみましょう。

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

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

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

(2) 次のページで好きな商品をいくつか選択(「選択」欄をクリック)
してください。

(3) 次のページに表示された商品のリストを確認してください。

ちゃんと選択した商品がリストされますね。
なお、購入個数にはデフォルトの1が表示されますね。



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


(次回に続く)


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