■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 2008年02月24日 楽しいJava講座 - 初心者から達人へのパスポート vol.093 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ [このメールマガジンは、画面を最大化して見てください。] ======================================================== ◆ 01.Tomcatのアプリケーション開発 ======================================================== さて、だんだんと何をやっているのか、わからなくなってきた人も いるのではないでしょうか。 私も、何をやっているのか、わからなくなってきました(おいおい)。 ...というのは冗談ですが、プログラムのファイルがどんどんと 増えてきてごちゃごちゃしてきましたので、念のために、これまで に作成してきた各プログラムの流れを頭の中で整理したうえで、 次のプログラミングにはいっていくことにしましょう。 ショッピングの通常の手順に合わせて、これまでのプログラムの流れ を整理すると、次のようになります。 -------------------------------------------------------- (0) 最初のページを呼び出す。 [WebブラウザーにURL(http://localhost:8080/JStudy2/itemSelect.html)を入力する] → itemSelect.html (1) キーワード(商品名の一部)やカテゴリーを入力して商品を検索する。 「送信」ボタンをクリックする → ItemServlet.java → itemList.jsp (2) 商品のリストが表示されるので、買いたい商品を選択する(= ショッ ピング・カートに入れる)。(ショッピング・カートは以後ときどき カートと略します。) 「選択した商品をカートに入れる」ボタンをクリックする → OrderItemServlet.java → cart.jsp (3) カートの中身が表示されるので、必要に応じて購入個数を変更する。 「選択した商品を購入する」ボタンをクリックする → OrderProcessServlet.java → order.jsp [例外:<<カートのオブジェクトが消失していた場合>> → OrderProcessServlet.java → cartmissing.html] -------------------------------------------------------- 前回は、(3)の場面において例外に対処するためのプログラミングを行いまし たが、上記の(3)の例外以外にもさまざまな場面で例外が発生する可能性が あります。 これらの例外については、あとでまとめて対処方法を説明いたします。 さて、(3)のあとは、以下のような処理が行えるようにプログラミングして いきましょう。(ただし例外の処理は、あと回し) -------------------------------------------------------- (4) 購入(注文)する内容が表示され、ユーザーIDとパスワードが要求される ので入力する。 「最終購入確認画面に進む」ボタンをクリックする → ConfirmOrderServlet.java → confirmOrder.jsp (5) 商品の発送先(= ユーザーの住所・氏名)が表示され、購入(注文)を 確定するかどうか聞いてくる。 「購入(注文確定)する」ボタンをクリックする → CompleteOrderServlet.java → completeOrder.jsp (6) 「注文を受け付けました。」のメッセージが表示される。 (これで終わり。) -------------------------------------------------------- ではこれから、ConfirmOrderServletのプログラミングにとりかかりたいと 思います。 このサーブレットでは、(3)のorder.jspのWebページに入力されたユーザーID からデータベースのCUSTOMERテーブルを検索し、住所と氏名を取り出します。 なお、パスワードや住所・氏名などの個人情報をそのままインターネット上に 流すとハッカーなどに読み取られる危険性がありますから、通常はSSL (Secure Socket Layer)やTLS(Transport Layer Security)というプロト コルを使って暗号化するのですが、ここら辺の話をするとなると、随分時間 がかかってしまいます。(公開鍵暗号方式(public key cryptosystem)とか 電子署名(digital signature)とか電子証明書(digital certificate)とか 認証局(CA = Certificate Authority)とかの話をしなければならなくなり ます。) しかも、こういったセキュリティーのお話は大変重要なので、あとでまとめて じゅうぶん時間をかけてお話したいと思います。 というわけで、今のところは、セキュリティー関連の部分は省略します。 パスワードも形式的に入力するだけにしておきます。 (あとでセキュリティーのお話のときにパスワード関連の部分も一緒に まとめてプログラミングします。) はい。では、ひとまずユーザーID(= 顧客番号)からデータベースのCUSTOMER テーブルを検索し、住所と氏名を取り出すようにするために、 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 = ?"; 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(); } } } -------------------------------------------------------- これも説明は不要ですね。 基本的にはselectData()というメソッドが追加されただけですね。 あと、リテラルで記述していたSQL文を変数に変えたという点も以前 と異なっていますが、本質的な違いではありません。 では続いて、次のような内容のConfirmOrderServletクラスを作成して ください。 このクラスは、正しいユーザーID(CUSTOMERテーブルのNUMカラムに 登録されている顧客番号)が入力されたら、顧客の住所と氏名を商品の 送付先として表示するJSP(confirmOrder.jsp)を呼び出します。 -------------------------------------------------------- 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.CustomerDbManager; import jp.co.flsi.lecture.webapp.entity.Customer; import jp.co.flsi.lecture.webapp.entity.Order; public class ConfirmOrderServlet 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"); if (anOrder == null) { getServletContext().getRequestDispatcher("/ordermissing.html").forward(req,res); } else { String customerNum = req.getParameter("userId"); if (customerNum == null) { getServletContext().getRequestDispatcher("/wrongUser.jsp").forward(req,res); } else { CustomerDbManager customerDb = new CustomerDbManager(); customerDb.selectData(customerNum); if (customerDb.getCustomerList().size() < 1) { getServletContext().getRequestDispatcher("/wrongUser.jsp").forward(req,res); } else { Customer customer = customerDb.getCustomerList().firstElement(); session.setAttribute("CUSTOMER",customer); getServletContext().getRequestDispatcher("/confirmOrder.jsp").forward(req,res); } } } } } -------------------------------------------------------- このソース・コードでは、カートがnullのときやユーザーIDが不正のときに、 それぞれordermissing.htmlやwrongUser.jspを呼び出すようにコーディング していますが、これらのエラー関連のファイルは、あとでまとめて作成する ことにします。 なお、顧客番号はCUSTOMERテーブルのプライマリー・キーになっていますから、 一つの顧客番号に対してはCUSTOMERテーブルのデータは1行しかありえません。 したがって、35行目の Customer customer = customerDb.getCustomerList().firstElement(); においては、VectorのfirstElement()メソッドを呼び出すことによって先頭の データ(これしかない)だけを取り出すようにしています。 あとの部分は、説明しなくても理解できることと思います。 では、このサーブレットを登録すべく、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> <servlet-name>OrderProcessServlet</servlet-name> <servlet-class>jp.co.flsi.lecture.webapp.servlet.OrderProcessServlet</servlet-class> </servlet> <servlet> <servlet-name>ConfirmOrderServlet</servlet-name> <servlet-class>jp.co.flsi.lecture.webapp.servlet.ConfirmOrderServlet</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> <servlet-mapping> <servlet-name>OrderProcessServlet</servlet-name> <url-pattern>/servlet/orderprocess</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ConfirmOrderServlet</servlet-name> <url-pattern>/servlet/confirmorder</url-pattern> </servlet-mapping> </web-app> -------------------------------------------------------- では、続いて次のようにconfirmOrder.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="completeorder" method="POST"> <TABLE border="1" width="100%"> <TBODY> <TR> <TH>商品番号</TH> <TH>商品名</TH> <TH>価格</TH> <TH>カテゴリー</TH> <TH>購入個数</TH> </TR> <%@ page import="jp.co.flsi.lecture.webapp.entity.*" %> <% int totalPrice = 0; %> <jsp:useBean class="jp.co.flsi.lecture.webapp.entity.Order" id="ORDER" scope="session" /> <% OrderItem anOrderItem; 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 align="right"><%= anOrderItem.getOrderQuantity() %></TD> </TR> <% totalPrice += anOrderItem.getPrice() * anOrderItem.getOrderQuantity(); } %> </TBODY> </TABLE> <BR> <TABLE border="1"> <TR> <TH>合計金額:</TH> <TH><%= totalPrice %>円</TH> </TR> </TABLE> <BR> <BR> <H1>商品の送付先:</H1> <jsp:useBean class="jp.co.flsi.lecture.webapp.entity.Customer" id="CUSTOMER" scope="session" /> <TABLE border="1"> <TR> <TH>郵便番号</TH> <TH>住所</TH> <TH>氏名</TH> </TR> <TR> <TD><%= CUSTOMER.getZipCode() %></TD> <TD><%= CUSTOMER.getAddress() %></TD> <TD><%= CUSTOMER.getName() %></TD> </TR> </TABLE> <BR> <BR> この内容で購入(注文)を確定するには、下の「購入(注文確定)する」ボタンを押してください。 <BR> <FONT color="#ff0000"><STRONG> なお、「購入(注文確定)する」ボタンを押すと注文が確定してしまい、取り消しはできませんのでご注意ください。 </STRONG></FONT> <BR> <BR> <INPUT TYPE="submit" NAME="completeOrder" VALUE="購入(注文確定)する"> </FORM> </BODY> </HTML> -------------------------------------------------------- このソース・コードの中で <FONT color="#ff0000">......</FORM> のFONTはフォントの種類を指定するためのタグで、そのcolor="#ff0000" という属性はフォントの色をRGB指定で赤色にするものです。また、 <STRONG>......</STRONG> のSTRONGは文字を強調表示することを指定するためのタグです。 残りのソース・コードは説明しなくても理解できますね。 ここまでできたところで、一度テストしてみましょう。 EclipseでTomcatを起動し、Webブラウザーを起動して、下記のURLを 入力してください。 http://localhost:8080/JStudy2/itemSelect.html (1) 「キーワード」欄、「カテゴリー」欄ともに何も入力せずに 「送信」ボタンをクリックしてみてください。 (2) 次のページ(商品リストのページ)で商品をいくつか選択(チェッ ク・マークを入れる)し、「選択した商品をカートに入れる」ボタン をクリックします。 (3) 選択した商品が次のページ(ショッピング・カートのページ)で リストされていることを確認し、「選択した商品を購入する」ボタン をクリックします。 (4) 次のページ(購入手続きのページ)で、ユーザーIDには J0001 などCUSTOMERテーブル上に存在する顧客番号を入力し、パスワードには tekitou など適当な値を入力して(あるいは入力しなくてもよい) 「最終購入確認画面に進む」ボタンをクリックします。 (5) 次のページに商品の送付先として顧客の郵便番号、住所、氏名が 表示されていることを確認してください。 どうですか?うまくいきましたか。 これ以降の部分は次回以降にプログラミングします。 (次回に続く) では、今日はここまでにします。 何か、わからないところがありましたら、下記の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. 不許無断複製 |