広告

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2010年03月28日

    Java総合講座 - 初心者から達人へのパスポート
                  vol.197

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


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:毎週日曜の夜に発行
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:毎週水曜の夜に発行
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


========================================================
◆ 01.Strutsのアプリケーション開発(プロジェクト:StrutsShop)
========================================================


では、次に、vol.188のアプリケーションの処理の流れのうち(U-7)〜(U-9)
までのプログラミングへと進んで行きましょう。

念のため、(U-7)〜(U-9)までの部分を抜粋し、再提示しておきます。

--------------------------------------------------------
(U-7) 注文のためのWebページが開く。
[order.jsp]

(U-8) (会員登録しない一時的な顧客の場合)顧客の住所・氏名・連絡先を
入力し、支払い方法(クレジット・カード払い/銀行振り込み)を選択し、
「注文内容の確認」ボタンを押す。
[confirmorder.do]→[ConfirmOrderAction.java]

(U-9) 注文確認のためのWebページが開く。
[confirmOrder.jsp]
--------------------------------------------------------



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


では、order.jspを下記のように編集しましょう。

--------------------------------------------------------
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-logic" prefix="logic" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@ taglib uri="/tags/struts-nested" prefix="nested" %>

<html:html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
      <title>購入手続き</title>
   </head>
   <body bgcolor="#77ffff" text="#fa5a00">
      <h1>購入する商品</h1>
      <html:form method="POST" action="/confirmorder">
         <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.struts.db.OrderItem" %>
             <% String homebase = request.getContextPath(); %>
            <% int totalPrice = 0; %>
             <bean:define id="orderItemList" name="ORDER" property="orderItems" type="Vector<OrderItem>" scope="session" />
            <logic:iterate id="item" type="OrderItem" name="orderItemList" scope="page">
               <tr>
                  <td><bean:write name="item" property="itemNum" /></td>
                  <td><bean:write name="item" property="itemName" /></td>
                  <td><bean:write name="item" property="price" />円</td>
                  <td><bean:write name="item" property="catName" /></td>
                  <td align="center"><bean:write name="item" property="orderQuantity" /></td>
                </tr>
                <% totalPrice += item.getPrice() * item.getOrderQuantity(); %>
            </logic:iterate>
           </tbody>
         </table>
         <br>
         <table border="1">
             <tr>
               <th>合計金額:</th>
               <th><%= totalPrice %>円</th>
             </tr>
         </table>
         <br>
         <br>
         お客様のお名前・ご住所等をご入力ください。
         <table border="0">
             <tr>
               <th>お名前:</th>
               <td><html:text property="name" size="20" /></td>
             </tr>
             <tr>
               <th>郵便番号:</th>
               <td><html:text property="zipcode" size="8" /></td>
             </tr>
             <tr>
               <th>ご住所:</th>
               <td><html:text property="address" size="100" /></td>
             </tr>
             <tr>
               <th>お電話番号:</th>
               <td><html:text property="telNo" size="12" /></td>
             </tr>
             <tr>
               <th>Eメール・アドレス:</th>
               <td><html:text property="emailAddress" size="30" /></td>
             </tr>
         </table>
         <br>
         <br>
         お支払い方法を選択してください。
         <table border="0">
             <tr>
               <th>お支払い方法:</th>
               <td>
               <html:select property="payMethod" value="0" size="2">
                 <html:option value="0">クレジット・カード払い</html:option>
                 <html:option value="1">銀行振り込み</html:option>
               </html:select>
              </td>
             </tr>
         </table>
         <br>
         <br>
         <html:submit property="submit" value="最終購入確認画面に進む" />
      </html:form>
      <br>
      <html:link page="/itemSelect.jsp">トップ・ページ(商品検索のページ)に戻る</html:link>
   </body>
</html:html>
--------------------------------------------------------

今回は、お支払い方法の選択肢として、クレジット・カード払いか銀行振り込み
のいずれかを選択させるために<html:option>というタグを使っています。
このタグは今回初めて出てきたと思います。(以前のvol.192でも似たような
パターンがありましたが、ただし<html:option>ではなく<html:options>という
タグを使って、コレクションからリストを表示させる方法を使っていました。)

この<html:option>は、選択肢をリスト表示させるためのタグで、

<html:option value="サーバーに送りたい値">表示したい文字列</html:option>

のように指定すると、Webブラウザー上では"表示したい文字列"が表示され、それを
選択すると、サーバー側へは"サーバーに送りたい値"が送信されます。

ここで、

<html:select property="payMethod" value="0" size="2">>
  <html:option value="0">クレジット・カード払い</html:option>
  <html:option value="1">銀行振り込み</html:option>
</html:select>

のように<html:select>タグにvalue属性を指定していることに注意して下さい。

たとえば<html:select>タグにvalue="0"という属性を指定しておくと、その下の

  <html:option value="0">クレジット・カード払い</html:option>

というオプションが最初に(デフォルトで)選択状態になります。
つまり、そのWebページが表示されたときに選択状態にしておきたい<html:option>タグの
value属性の値を<html:select>タグのvalue属性に指定しておくのです。

また、<html:select>タグにsize属性を指定しておくと、リストの高さが
size属性に指定した分だけ広がります。
ここではsize属性に2という値を指定してあるので、リストの高さが2行分
になります。


ところでこのJSPのように、個人情報を入力させるWebページはSSL(Secure Socket Layer)
を使ってインターネット上では暗号化して送信するのが常識ですが、SSLについては
後の上級コースでお話することにし、ここでは使用しません。
(特にクレジット・カード番号など秘密の情報を送信するときはSSLなどの
セキュリティー技術を使用することが不可欠になります。)



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


次に、上記のorder.jspのFORMに対するActionFormのクラスをOrderFormという名前で
作成しましょう。

(1) プロジェクト・エクスプローラー内でjp.co.flsi.lecture.strutsを右クリック
し、「新規」→「その他」を選択します。

(2) 「新規」ウインドウにおいて「Amateras」配下の「Struts」配下の
「Struts ActionForm」を選択し、「次へ」ボタンをクリックします。

(3) 「名前」欄に

OrderForm

と入力し、「完了」ボタンをクリックします。

(4) OrderForm.javaのエディターが開いたら、下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.struts;

import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

public class OrderForm extends ActionForm {
   private static Logger logger = Logger.getLogger(OrderForm.class);
   private String name = null;
   private String zipcode = null;
   private String address = null;
   private String telNo = null;
   private String emailAddress = null;
   private String payMethod = null;

   public void reset(ActionMapping mapping, HttpServletRequest request) {
      logger.info("Start ...............");
      try {
         request.setCharacterEncoding("UTF-8");
      } catch (UnsupportedEncodingException e) {
         logger.error(e, e);
      }
      finally {
         logger.info("End ...............");
      }
   }

   public void setName(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }

   public void setZipcode(String zipcode) {
      this.zipcode = zipcode;
   }

   public String getZipcode() {
      return zipcode;
   }

   public void setAddress(String address) {
      this.address = address;
   }

   public String getAddress() {
      return address;
   }

   public void setTelNo(String telNo) {
      this.telNo = telNo;
   }

   public String getTelNo() {
      return telNo;
   }

   public void setEmailAddress(String emailAddress) {
      this.emailAddress = emailAddress;
   }

   public String getEmailAddress() {
      return emailAddress;
   }

   public void setPayMethod(String payMethod) {
      this.payMethod = payMethod;
   }

   public String getPayMethod() {
      return payMethod;
   }

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

なお、入力データの検証については、会員登録している顧客の場合との
兼ね合いもあるため、後の記事でまとめてコーディングすることにします。
今回は検証なしで済ませます。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


では、このOrderFormを下記のようにして、struts-config.xmlに登録することに
しましょう。

まず、struts-config.xmlの中の

--------------------------------------------------------
  <form-beans>
    <form-bean name="itemSelectForm" type="jp.co.flsi.lecture.struts.ItemSelectForm" />
    <form-bean name="itemListForm" type="jp.co.flsi.lecture.struts.ItemListForm" />
    <form-bean name="cartForm" type="jp.co.flsi.lecture.struts.CartForm" />
  </form-beans>
--------------------------------------------------------

の部分を

--------------------------------------------------------
  <form-beans>
    <form-bean name="itemSelectForm" type="jp.co.flsi.lecture.struts.ItemSelectForm" />
    <form-bean name="itemListForm" type="jp.co.flsi.lecture.struts.ItemListForm" />
    <form-bean name="cartForm" type="jp.co.flsi.lecture.struts.CartForm" />
    <form-bean name="orderForm" type="jp.co.flsi.lecture.struts.OrderForm" />
  </form-beans>
--------------------------------------------------------

というように編集しましょう。orderFormという名前の<form-bean>を追加しただけですね。


続いて、struts-config.xmlの中の

--------------------------------------------------------
    <action path="/confirmorder" type="jp.co.flsi.lecture.struts.ConfirmOrderAction"
     input="/order.jsp">
      <forward name="success" path="/confirmOrder.jsp"/>
    </action>
--------------------------------------------------------

の部分を

--------------------------------------------------------
    <action path="/confirmorder" type="jp.co.flsi.lecture.struts.ConfirmOrderAction"
     name="orderForm" scope="request" input="/order.jsp">
      <forward name="success" path="/confirmOrder.jsp"/>
    </action>
--------------------------------------------------------

というように編集して下さい。
つまり、order.jspのFORMにorderFormを対応付けます。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


さて、現在は会員登録しない一時的な顧客の場合だけを対象としてプログラミング
していますが、一時的な顧客といえどもちゃんとデータベースに記録しておく必要
があります。

顧客の情報は、決済(支払い)が済んで商品の配達が完了するまで、いや、それだけ
でなく、あとで顧客からクレームや返品の依頼や問合せなどが来る可能性もあります
から、配達が完了した後も当分の間は顧客の情報を保管しておかなければなりません。

結局のところ、一時的な顧客といえどもシステム上では会員登録している顧客と
ほとんど同様にデータベースに保管する必要があるのです。


というわけで、入力された顧客の情報をデータベース(USERテーブル)に登録する必要
がありますから、ここでUSERテーブルにマッピングするエンティティーのクラスを作成
しておきましょう。


しかし、その前にUSERテーブルの内容を振り返ってみましょう。

USERテーブルのカラムを確認すると、たとえばテーブル作成時(vol.186参照)の
SQL文を見ると

--------------------------------------------------------
create table USER (
U_TYPE char(1) not null,
USERID char(7) not null,
PASS varbinary(20) not null,
NAME varchar(20) not null,
ZIPCODE char(8) not null,
ADDRESS varchar(100) not null,
primary key(U_TYPE, USERID)
);
--------------------------------------------------------

となっており、電話番号やEメール・アドレスを入れるカラムは作成していません
でした。これでは、先ほどのorder.jspのWebページで入力された顧客情報のうち
電話番号やEメール・アドレスをテーブルに保管することはできません。

というわけで、まずUSERテーブルを変更してカラムを追加する作業を行って
おきましょう。


これにはALTER TABLEというSQL文を使います。

(vol.186と同様にしてSQLの実行を行うことにしましょう。)

まずは、下記のようなSQLのファイルを作成しましょう。
これは見て分かるように、USERテーブルにTELNOとEMAILというカラムを追加する
ためのSQL文です。

--------------------------------------------------------
alter table USER add TELNO char(12), add EMAIL char(30);
--------------------------------------------------------

これは、C:\JavaWorkSpaceフォルダーの中に、
ALTER_USER.sql
というファイル名で保管しておきましょう。

続いて、以下のようにMySQLのコマンド・ライン・クライアントを起動して作業を
行いましょう。

(1) 「スタート」ボタン→「すべてのプログラム」→「MySQL」→
「MySQL Server 5.0」→「MySQL Command Line Client」
を選択します。

(2) rootのパスワードを聞いてきますので

rootpass

を入力しましょう。

(3) 続いて、STRUSHOPデータベースを使用(接続)するために以下の
コマンドを入力します。

use STRUSHOP

(4) 以下のコマンドで(先ほど保管したファイルを使って)テーブルを変更
しましょう。

source C:\JavaWorkSpace\ALTER_USER.sql

(5) 最後に、MySQLのコマンド・ライン・クライアントを終了しましょう。

quit



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


では、USERテーブルにマッピングするエンティティー・クラスを作成しましょう。
(テーブルにマッピングするクラスをエンティティー・クラス(entity class)
と呼ぶことがあります。あるいは、データベースのテーブル以外であっても同様に
永続的に保管されるデータにマッピングするクラスをエンティティー・クラスと
呼ぶことがあります。)

(1) プロジェクト・エクスプローラー内でjp.co.flsi.lecture.struts.dbを右クリック
し、「新規」→「クラス」を選択します。

(2) 「名前」欄に

User

と入力し、「完了」ボタンをクリックします。

(3) User.javaのエディターが開いたら、下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.struts.db;

import java.io.Serializable;

public class User implements Serializable {
      private String userType = "";
      private String userid = "";
      private byte[] password = new byte[] {};
      private String name = "";
      private String zipcode = "";
      private String address = "";
      private String telno = "";
      private String email = "";

   public void setUserType(String userType) {
      this.userType = userType;
   }

   public String getUserType() {
      return userType;
   }

   public void setUserid(String userid) {
      this.userid = userid;
   }

   public String getUserid() {
      return userid;
   }

   public void setPassword(byte[] password) {
      this.password = password;
   }

   public byte[] getPassword() {
      return password;
   }

   public void setName(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }

   public void setZipcode(String zipcode) {
      this.zipcode = zipcode;
   }

   public String getZipcode() {
      return zipcode;
   }

   public void setAddress(String address) {
      this.address = address;
   }

   public String getAddress() {
      return address;
   }

   public void setTelno(String telno) {
      this.telno = telno;
   }

   public String getTelno() {
      return telno;
   }

   public void setEmail(String email) {
      this.email = email;
   }

   public String getEmail() {
      return email;
   }

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

ここで、passwordがbyteの配列型であることに注意して下さい。
これは、USERテーブルのPASSカラムがvarbinary型であることに対応した
ものです。このようにカラムがvarbinary型の場合は、それにマッピング
するフィールドはbyteの配列型にしておきます。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


続いて、USERテーブルへデータを登録したり検索を行うためのクラスを作成しましょう。

(1) プロジェクト・エクスプローラー内でjp.co.flsi.lecture.struts.dbを右クリック
し、「新規」→「クラス」を選択します。

(2) 「名前」欄に

UserDbManager

と入力し、「完了」ボタンをクリックします。

(3) UserDbManager.javaのエディターが開いたら、下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.struts.db;

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

import jp.co.flsi.lecture.reflect.ValueLogStringMaker;
import org.apache.log4j.Logger;

public class UserDbManager extends DbManager {
   private static Logger logger = Logger.getLogger(UserDbManager.class);
   private String selectMaxTempUseridSql = "SELECT MAX(USERID) FROM USER WHERE U_TYPE = 'T'";
   private static final String selectUserTypeAndUseridSql = "SELECT * FROM USER WHERE U_TYPE = ? AND USERID = ?";
   private static final String insertSql = "INSERT INTO USER VALUES (?, ?, ?, ?, ?, ?, ?, ?)";

   public String getMaxTemporaryUserid() throws StruShopDbException {
      logger.info("Start ...............");
      ValueLogStringMaker stringMaker = new ValueLogStringMaker();
        String maxTempUserid = null;
      try {
            Statement selectSt = conn.createStatement();
            ResultSet rs = selectSt.executeQuery(selectMaxTempUseridSql);
            if (rs.next()) maxTempUserid = rs.getString(1);
            if (maxTempUserid == null) maxTempUserid =  "0000000";
            selectSt.close();
      }
      catch (SQLException e) {
         logger.error(e, e);
         throw new StruShopDbException("Error: getMaxTemporaryUserid() failed!", e);
      }
      catch (Throwable e) {
         logger.error(e, e);
      }
      finally {
         logger.info("End ...............");
      }
      logger.info("Method return: <<<<<" + stringMaker.getValues("maxTempUserid", maxTempUserid));
      logger.info(">>>>>");
      return maxTempUserid;
   }

   public User getDataByUserTypeAndUserid(String userType, String userid) throws StruShopDbException {
      logger.info("Start ...............");
      ValueLogStringMaker stringMaker = new ValueLogStringMaker();
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("userType", userType));
      logger.info(">>>>>");
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("userid", userid));
      logger.info(">>>>>");
      User user = new User();
      try {
         PreparedStatement selectPs = null;
         ResultSet rs;
         if (userType == null) {
            userType = "";
         }
         if (userid == null) {
            userid = "";
         }
         selectPs = conn.prepareStatement(selectUserTypeAndUseridSql);
         selectPs.setString(1, userType);
         selectPs.setString(2, userid);
         rs = selectPs.executeQuery();
         while (rs.next()) {
            user.setUserType(rs.getString("U_TYPE"));
            user.setUserid(rs.getString("USERID"));
            user.setPassword(rs.getBytes("PASS"));
            user.setName(rs.getString("NAME"));
            user.setZipcode(rs.getString("ZIPCODE"));
            user.setAddress(rs.getString("ADDRESS"));
            user.setTelno(rs.getString("TELNO"));
            user.setEmail(rs.getString("EMAIL"));
         }
         selectPs.close();
      }
      catch (SQLException e) {
         logger.error(e, e);
         throw new StruShopDbException("Error: getDataByUserTypeAndUserid() failed!", e);
      }
      catch (Throwable e) {
         logger.error(e, e);
      }
      finally {
         logger.info("End ...............");
      }
      logger.info("Method return: <<<<<" + stringMaker.getValues("user", user));
      logger.info(">>>>>");
      return user;
   }

   public boolean insertData(User user) throws StruShopDbException {
      logger.info("Start ...............");
      ValueLogStringMaker stringMaker = new ValueLogStringMaker();
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("user", user));
      logger.info(">>>>>");
      try {
         conn.setAutoCommit(false);
         PreparedStatement insertPs = conn.prepareStatement(insertSql);
         insertPs.setString(1, user.getUserType());
         insertPs.setString(2, user.getUserid());
         insertPs.setBytes(3, user.getPassword());
         insertPs.setString(4, user.getName());
         insertPs.setString(5, user.getZipcode());
         insertPs.setString(6, user.getAddress());
         insertPs.setString(7, user.getTelno());
         insertPs.setString(8, user.getEmail());
         insertPs.executeUpdate();
         insertPs.close();
         conn.commit();
      }
      catch (SQLException e) {
         logger.error(e, e);
         throw new StruShopDbException("Error: insertData() failed!", e);
      }
      catch (Throwable e) {
         logger.error(e, e);
         return false;
      }
      finally {
         logger.info("End ...............");
      }
      logger.info("Method return: <<<<< true");
      logger.info(">>>>>");
      return true;
   }

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

以上のソース・コードのうち

user.setPassword(rs.getBytes("PASS"));

という行と

insertPs.setBytes(3, user.getPassword());

という行に注意して下さい。

このように、データベースのvarbinary型のカラムからデータを取り出すには、
ResultSetのgetBytes()メソッド(これの戻り値はbyteの配列型)を使い、データ
を書き込むにはPreparedStatementのsetBytes()メソッド(これの第二引数は
byteの配列型)を使います。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


(次回に続く)


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



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      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) 2010 Future Lifestyle Inc. 不許無断複製