■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 2008年03月23日 楽しいJava講座 - 初心者から達人へのパスポート vol.096 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ [このメールマガジンは、画面を最大化して見てください。] ======================================================== ◆ 01.Tomcatのアプリケーション開発 ======================================================== では、前回整理した前提条件について考察し、前提条件が満たされていない ときの対処をプログラミングしていきましょう。 このうち、オプションになっているものは、条件が満たされて いなくてもかまわないものなので、無視します。 そうすると、(操作1)と(操作2)は無視できます。 では、(操作3)はどうでしょうか。 (前回、「カートのオブジェクトの中に商品(OrderItem)オブジェクトが が入っていること。」という前提条件を書き忘れていたので、それを追記した ものを下記に提示します。(注文する商品がないのに購入手続きへ進めるわけ にはいきませんので、この前提条件は必要です。)) -------------------------------------------------------- (操作3) 購入個数の変更 ---------------------------------- ■入力ページ: ・[cartページ] ■前提条件: ・[cartページ]において商品の購入個数が変更されていること(オプション) ・[cartページ]において「選択した商品を購入する」ボタンをクリック すること。 ・セッション・オブジェクトの中にカートのオブジェクト が入っていること。 <<条件が満たされていない場合→エラー・メッセージ:cartmissing.html>> ・購入対象の商品 = 購入個数の変更対象になる商品(OrderItem)オブジェクトが 既にカートのオブジェクトの中に入っていること。 また、カートのオブジェクトの中に商品(OrderItem)オブジェクトが が入っていること(カートが空でないこと)。 <<条件が満たされていない場合→エラー・メッセージ:orderiteminvalid.html>> ■事後条件: ・セッション・オブジェクトの中にカートのオブジェクト が入っていること。 ■結果ページ: ・[orderページ] ---------------------------------- [cartページ]→ OrderProcessServlet.java → order.jsp ---------------------------------- (操作3)の前提条件のうち、セッション・オブジェクトの中にカートのオブジェクト が入っていない場合にcartmissing.htmlのWebページでエラー・メッセージを返す ことについては、すでにvol.092で実装しました。 しかし、セッション・オブジェクトの中にショッピング・カートのオブジェクト が入っている場合でも、次のような問題が生じる場合があります。 一度ショッピング・カートの中から商品を削除(購入個数を0にする)した後、 Webブラウザーの「戻る」ボタンをクリックするなどして商品を削除する前の ページに戻った場合、ショッピング・カートのオブジェクト内ではその商品は 無くなっているのに、Webページ上ではその商品はあることになります。 つまり、Webページ上の内容とセッション・オブジェクトにはいっているショッ ピング・カートのオブジェクトの内容に食い違いが生じることになります。 このように食い違いが生じた場合には、Webページ上の情報でセッション・オブ ジェクトにはいっているショッピング・カートを書き換える(目に見えている Webページの情報のほうを優先する)というようにしてもいいのですが、当メール マガジンでは、この状態をはっきりとわかるようにするために、エラーとして メッセージを返すことにします。 そのため、 -------------------------------------------------------- ・購入対象の商品 = 購入個数の変更対象になる商品(OrderItem)オブジェクトが 既にカートのオブジェクトの中に入っていること。 -------------------------------------------------------- という前提条件にして、この前提条件が満たされていないときはエラー・メッセー ジとしてorderiteminvalid.htmlというWebページを返すことにしています。 では、この前提条件が満たされていないときにorderiteminvalid.htmlを返すよう にするために、OrderProcessServletを下記のように編集しましょう。 -------------------------------------------------------- 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 javax.servlet.http.HttpSession; import jp.co.flsi.lecture.webapp.entity.Order; import jp.co.flsi.lecture.webapp.entity.OrderItem; public class OrderProcessServlet 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("/cartmissing.html").forward(req,res); } else { Enumeration paramNames = req.getParameterNames(); // Webページ上の購入対象の商品がカートの中に入っていることのチェック用フラグ boolean orderItemFoundInCart = false; // falseは「カートにない」を意味する while(paramNames.hasMoreElements()) { String aParamName = (String)paramNames.nextElement(); if (!aParamName.equals("putIntoOrder")) { OrderItem anOrderItem = new OrderItem(); orderItemFoundInCart = false; // チェック用フラグを「カートにない」にリセット for (OrderItem oi : anOrder.getOrderItems()) { if(aParamName.substring(0, 5).equals(oi.getNum())) { orderItemFoundInCart = true; // チェック用フラグを「カートにある」にセット anOrderItem.setNum(oi.getNum()); anOrderItem.setName(oi.getName()); anOrderItem.setPrice(oi.getPrice()); anOrderItem.setImage(oi.getImage()); anOrderItem.setCategory(oi.getCategory()); anOrderItem.setOrderQuantity(Integer.parseInt((String)req.getParameter(aParamName))); } } if (!orderItemFoundInCart) { break; } else { anOrder.removeOrderItem(anOrderItem); if (anOrderItem.getOrderQuantity() > 0) { anOrder.addOrderItem(anOrderItem); } if (anOrder.getOrderItems().size() < 1) { orderItemFoundInCart = false; } } } } if (!orderItemFoundInCart) { getServletContext().getRequestDispatcher("/orderiteminvalid.html").forward(req,res); } else { session.setAttribute("ORDER",anOrder); getServletContext().getRequestDispatcher("/order.jsp").forward(req,res); } } } public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { getServletContext().getRequestDispatcher("/bookmarkinvalid.html").forward(req,res); } } -------------------------------------------------------- ここでは、新たにorderItemFoundInCartという変数を用意して、Webページにリスト されている商品がカートのオブジェクトの中に見つかった場合にはorderItemFoundInCart の値をtrueにし、見つからなかった場合にはfalseのままにして、Webページを返す 時点でorderItemFoundInCartがfalseのときには、order.jspの代わりに orderiteminvalid.htmlを呼び出すように編集を加えています。 また上記のソース・コードでは、カートの中が空っぽの場合にもorderItemFoundInCart がfalseになりますので、「カートのオブジェクトの中に商品(OrderItem)オブジェ クトがが入っていること(カートが空でないこと)。」という前提条件が満たされて いないときにもorderiteminvalid.htmlが呼び出されることになります。 なお、orderItemFoundInCartの値がfalseのときは、Webページにリストされている 商品がカートのオブジェクトの中に見つからないことを意味し、trueのときは見つ かったことを意味しますが、このように何かの判断のために使用する変数(主に trueかfalseといった二者択一の値を保持する場合が多い)を「フラグ(flag)」と呼ぶ ことがあります。これは、旗(flag)が信号として使われていたこと(旗を揚げるか 揚げないかで合図を送ったこと)に由来します。 では、エラー・メッセージを返すためのWebページとして、次のような orderiteminvalid.htmlを作成しておきましょう。 (itemSelect.htmlと同じ場所に作成してください。) -------------------------------------------------------- <HTML> <HEAD> <TITLE>カート・データ不正</TITLE> </HEAD> <BODY bgcolor="#77ffff" text="#fa5a00"> <H1>カート・データ不正</H1> 現在のショッピング・カートの情報とWebページの情報に整合性がないか、もしくは <BR> ショッピング・カートの中に商品がないため、購入手続きに進むことができません。 <BR> まことに申し訳ありませんが、商品の検索から再度やり直してください。 <BR> <BR> <A href="http://localhost:8080/JStudy2/itemSelect.html"> 商品の検索に戻るには、ここをクリック </A> <BR> </BODY> </HTML> -------------------------------------------------------- では、このWebページがちゃんと表示されるか、テストしてみましょう。 EclipseでTomcatを起動し、Webブラウザーを起動して、下記のURLを 入力してください。 http://localhost:8080/JStudy2/itemSelect.html (1) 「キーワード」欄、「カテゴリー」欄ともに何も入力せずに 「送信」ボタンをクリックしてみてください。 (2) 次のページ(商品リストのページ)でどれか2つの商品を選択(チェッ ク・マークを入れる)[たとえば「製品001」と「製品002」を選択]し、 「選択した商品をカートに入れる」ボタンをクリックします。 (3) 選択した商品が次のページ(ショッピング・カートのページ)でリスト されていることを確認し、このうちの一つの商品([たとえば「製品002」) の「購入個数」を0に変更し、「選択した商品を購入する」ボタンをクリッ クします。 (4) 次のページ(購入手続きのページ)で、「製品002」が無くなっている (さきほど購入個数を0に変更していたので、カートから削除されている) ことを確認し、Webブラウザーの「戻る」ボタンをクリックして(3)のページ に戻ります。 (5) 今度は「製品002」の「購入個数」を10にして、「選択した商品を購入する」 ボタンをクリックします。 (6) Webページ上の商品がセッション・オブジェクト内のショッピング・カート のものと食い違っているために、「カート・データ不正」のページが表示さ れ、 -------------------------------------------------------- 現在のショッピング・カートの情報とWebページの情報に整合性がないか、もしくは ショッピング・カートの中に商品がないため、購入手続きに進むことができません。 まことに申し訳ありませんが、商品の検索から再度やり直してください。 -------------------------------------------------------- というメッセージが表示されますね。 これがorderiteminvalid.htmlのWebページです。 では、次に(操作4)の前提条件を見て見ましょう。 -------------------------------------------------------- (操作4) ユーザーIDに対応した住所・氏名の取り出し ---------------------------------- ■入力ページ: ・[orderページ] ■前提条件: ・[orderページ]において正しいユーザーIDが入力されていること <<条件が満たされていない場合→エラー・メッセージ:wrongUser.jsp>> ・[orderページ]において正しいパスワードが入力されていること (本来は必須だが、今のところオプションとしておく) ・[orderページ]において「最終購入確認画面に進む」ボタンをクリック すること。 ・セッション・オブジェクトの中にカートのオブジェクト が入っていること。 <<条件が満たされていない場合→エラー・メッセージ:ordermissing.html>> ・カートのオブジェクトの中に商品(OrderItem)オブジェクトが が入っていること。 <<条件が満たされていない場合→エラー・メッセージ:invalidorder.html>> ■事後条件: ・Customerオブジェクトがセッション・オブジェクトの中にはいっていること。 ■結果ページ: ・[confirmOrderページ]:商品の発送先(= ユーザーの住所・氏名)が表示され、 購入(注文)を確定するかどうか聞いてくる。 ---------------------------------- [orderページ]→ ConfirmOrderServlet.java → confirmOrder.jsp ---------------------------------- まず -------------------------------------------------------- ・セッション・オブジェクトの中にカートのオブジェクト が入っていること。 <<条件が満たされていない場合→エラー・メッセージ:ordermissing.html>> -------------------------------------------------------- については、すでにvol.093で、カートの変数anOrderにオブジェクトを代入した ときの値がnull(これはカートのオブジェクトが無く、変数が空であることを意味 する)のときにordermissing.htmlを呼び出すようにプログラミングしていました が、ordermissing.html自体はまだ作成していませんでした。 というわけで、下記のようなordermissing.htmlのファイルを作成しましょう。 (これも同じくitemSelect.htmlと同じ場所に作成してください。) -------------------------------------------------------- <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> -------------------------------------------------------- 続いて、 -------------------------------------------------------- ・[orderページ]において正しいユーザーIDが入力されていること <<条件が満たされていない場合→エラー・メッセージ:wrongUser.jsp>> -------------------------------------------------------- についても、wrongUser.jspの呼び出しは既にプログラミングしていましたが、 wrongUser.jsp自体はまだ作成しておりません。 というわけで、下記のようなwrongUser.jspのファイルを作成しましょう。 (これも同じくitemSelect.htmlと同じ場所に作成してください。) -------------------------------------------------------- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="Shift_JIS" %> <HTML> <HEAD> <TITLE>ユーザーIDエラー</TITLE> </HEAD> <BODY bgcolor="#77ffff" text="#fa5a00"> <H1>ユーザーIDエラー</H1> <% String user = request.getParameter("userId"); %> 入力されたユーザーID(<%= user %>)またはパスワードは正しくありません。 <BR> 前のページに戻って、ユーザーID/パスワードの入力をやり直してください。 <BR> <BR> <FORM> <INPUT TYPE="button" VALUE="前のページに戻る" onClick="history.back()"> </FORM> </BODY> </HTML> -------------------------------------------------------- ここで、 -------------------------------------------------------- <INPUT TYPE="button" VALUE="前のページに戻る" onClick="history.back()"> -------------------------------------------------------- というコードが新しく出てきましたが、これは前のWebページに戻るためのボタン を表示するコードです。Webブラウザーの「戻る」ボタンと同じ働きをします。 なお、このページではサーブレット(ConfirmOrderServlet)からuserIdの値を 引き継ぐために、HTMLファイルではなくJSPファイルにしています。 ┌補足─────────────────────────┐ このuserIdの値は[orderページ]に入力されたものがrequestオブジェクトの パラメーターとして保持され、サーブレット(ConfirmOrderServlet)から wrongUser.jspにforward() -------------------------------------------------------- getServletContext().getRequestDispatcher("/wrongUser.jsp").forward(req,res); -------------------------------------------------------- されたものです。 サーブレットで -------------------------------------------------------- String customerNum = req.getParameter("userId"); -------------------------------------------------------- というコードで取り出したの同じく、JSPでも -------------------------------------------------------- <% String user = request.getParameter("userId"); %> -------------------------------------------------------- という同様のJavaコードで取り出せます。 JSPでは、HttpServletRequestオブジェクトがrequestという変数で 表される決まりになっていることを思い出してください。 └───────────────────────────┘ では、このwrongUser.jspが正しく機能するかどうか、テストしてみましょう。 EclipseでTomcatを起動し、Webブラウザーを起動して、下記のURLを 入力してください。 http://localhost:8080/JStudy2/itemSelect.html (1) 「キーワード」欄、「カテゴリー」欄ともに何も入力せずに 「送信」ボタンをクリックしてみてください。 (2) 次のページ(商品リストのページ)で商品をいくつか選択(チェッ ク・マークを入れる)し、「選択した商品をカートに入れる」ボタン をクリックします。 (3) 選択した商品が次のページ(ショッピング・カートのページ)で リストされていることを確認し、「選択した商品を購入する」ボタン をクリックします。 (4) 次のページ(購入手続きのページ)で、ユーザーIDに aaaaa などCUSTOMERテーブル上には存在しない文字列を入力し、パスワードには tekitou など適当な値を入力して(あるいは入力しなくてもよい) 「最終購入確認画面に進む」ボタンをクリックします。 (5) 次に「ユーザーIDエラー」のページが表示され、 -------------------------------------------------------- 入力されたユーザーID(aaaaa)またはパスワードは正しくありません。 前のページに戻って、ユーザーID/パスワードの入力をやり直してください。 -------------------------------------------------------- というようなメッセージが表示されますね。 これがwrongUser.jspののWebページです。 これでOKですね。 では、最後の前提条件 -------------------------------------------------------- ・カートのオブジェクトの中に商品(OrderItem)オブジェクトが が入っていること。 <<条件が満たされていない場合→エラー・メッセージ:invalidorder.html>> -------------------------------------------------------- を見てみましょう。 これは、カートの中に商品が入っていない場合には注文手続きをするわけには いきませんので、エラー・メッセージを返させるようにするものです。 この部分はまだプログラミングしていなかったので、やっておきましょう。 ConfirmOrderServletを下記のように編集します。 -------------------------------------------------------- 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 if (anOrder.getOrderItems().size() < 1) { getServletContext().getRequestDispatcher("/invalidorder.html").forward(req,res); } else { Customer customer = customerDb.getCustomerList().firstElement(); session.setAttribute("CUSTOMER",customer); getServletContext().getRequestDispatcher("/confirmOrder.jsp").forward(req,res); } } } } public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { getServletContext().getRequestDispatcher("/bookmarkinvalid.html").forward(req,res); } } -------------------------------------------------------- 何が変わったかわかりますね。 -------------------------------------------------------- else if (anOrder.getOrderItems().size() < 1) { getServletContext().getRequestDispatcher("/invalidorder.html").forward(req,res); } -------------------------------------------------------- というコードが追加されただけです。 では、続いて下記のようなinvalidorder.htmlファイルを作成してください。 (itemSelect.htmlと同じ場所に作成してください。) -------------------------------------------------------- <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ページまで質問を お寄せください。 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: 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. 不許無断複製 |