広告 |
---|
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 2010年04月25日 Java総合講座 - 初心者から達人へのパスポート vol.201 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ------------------------------------------------------- ・現在、このメールマガジンは以下の2部構成になっています。 [1] 当初からのコース:毎週日曜の夜に発行 これは現在、中級レベルになっています。 [2] 2009年11月開講コース:毎週水曜の夜に発行 これは現在、初心者向けのレベルになっています。 ・このメールマガジンは、画面を最大化して見てください。 小さな画面で見ていると、不適切な位置で行が切れてしまう など、問題を起すことがあります。 ・このメールマガジンに掲載されているソース・コード及び 文章は特に断らない限り、すべて筆者が著作権を所有してい ます。また、これらのソース・コードは学習用のためだけに 提供しているものです。 ------------------------------------------------------- ======================================================== ◆ 01.Strutsのアプリケーション開発(プロジェクト:StrutsShop) ======================================================== 前回までで、インターネット・ショッピングのアプリケーションの処理の 基本的な流れの実装は終わりましたので、今回からは副次的な流れのプログ ラミングにはいっていきます。 まずは、これまでに出てきた -------------------------------------------------------- (U-7) 注文のためのWebページが開く。 [order.jsp] (U-8) (会員登録しない一時的な顧客の場合)顧客の住所・氏名・連絡先を 入力し、支払い方法(クレジット・カード払い/銀行振り込み)を選択し、 「注文内容の確認」ボタンを押す。 [confirmorder.do]→[ConfirmOrderAction.java] (U-9) 注文確認のためのWebページが開く。 [confirmOrder.jsp] -------------------------------------------------------- という処理の流れの副次的な流れとして、 (a) これから会員登録する顧客の場合 (b) 既に会員登録済みの顧客の場合 を考えます。 まず(a)に対しては -------------------------------------------------------- (U-7) 注文のためのWebページが開く。 [order.jsp] (U-8a-1) (これから会員登録する顧客の場合)「新規に会員登録する」 という項目を選択する。支払い方法(クレジット・カード払い/銀行振り込み) を選択し、「注文内容の確認」ボタン(「新規会員登録」ボタンも兼務) を押す。 [confirmorder.do]→[ConfirmOrderAction.java] (U-8a-2) 会員登録のためのWebページが開く。 [userReg.jsp] (U-8a-3) 顧客の住所・氏名・連絡先・ユーザーID・パスワードを入力し、 「会員登録」ボタンを押す。 [userreg.do]→[UserRegistrationAction.java] (U-9) 注文確認のためのWebページが開く。 [confirmOrder.jsp] -------------------------------------------------------- という処理の流れを考えます。 ただし、上記のうち(U-8a-3)〜(U-9)に対しては、さらに下記のような 副次的な流れが考えられます。 -------------------------------------------------------- (U-8a-3) 顧客の住所・氏名・連絡先・ユーザーID・パスワードを入力し、 「会員登録」ボタンを押す。 [userreg.do]→[UserRegistrationAction.java] (U-8a-3r-1) (ユーザーIDが既存のものと重複していた場合)会員登録の ためのWebページが再度開く。このとき「重複エラー」を表示する。 [userReg.jsp] (U-8a-3r-2) 顧客の住所・氏名・連絡先・ユーザーID・パスワードを入力し直し、 「会員登録」ボタンを押す。 [userreg.do]→[UserRegistrationAction.java] (U-9) 注文確認のためのWebページが開く。 [confirmOrder.jsp] -------------------------------------------------------- では、これらの処理の流れをプログラミングしていきましょう。 ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ まず、order.jspに (a) これから会員登録する顧客の場合 (b) 既に会員登録済みの顧客の場合 の選択肢のためのコードを加えます。 では、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: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:errors property="membership" /> <html:radio property="membership" value="new"/> 新規に会員登録する <br> <br> <html:radio property="membership" value="yes"/> 会員登録済み(ユーザーIDとパスワードを入力して下さい。) <br> <html:errors property="userid" /> <html:errors property="password" /> <table border="0"> <tr> <th>ユーザーID:</th> <td><html:text property="userid" size="7" /></td> </tr> <tr> <th>パスワード:</th> <td><html:password property="password" size="10" redisplay="false" /></td> </tr> </table> <br> <html:radio property="membership" value="no"/> 会員登録せずに購入する(下の各欄にお客様のお名前・ご住所等をご入力ください。) <br> <html:errors property="name" /> <html:errors property="zipcode" /> <html:errors property="address" /> <html:errors property="telNo" /> <html:errors property="emailAddress" /> <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> <html:submit property="submit" value="最終購入確認または新規会員登録の画面に進む" /> </html:form> <br> <html:link page="/itemSelect.jsp">トップ・ページ(商品検索のページ)に戻る</html:link> </body> </html:html> -------------------------------------------------------- ここで新たに<html:radio>タグと<html:password>タグが登場しました。 <html:radio>タグは見てわかる通り、ラジオ・ボタンのタグです。 ここでは、property属性に"membership"という値を指定した<html:radio>タグ が2つ書かれていますが、そうするとこのどちらか一方だけをオンにする(クリッ クするとマークが付く)ことができます。そして、オンになったほうのvalue属性 の値がサーバーに送られることになります。 <html:password>タグは見てわかる通り、パスワードを入力させるためのタグです。 <html:text>タグと同じように文字列の入力ができますが、<html:text>タグと違っ て文字列はアスタリスク(*)に変換されて表示されます。 このタグのredisplayという属性は、予め値が設定されているときにそれを表示 するかどうかを指定するもので(ただし画面上はアスタリスクで表示されるので 文字列は見えない)、redisplay="false"を指定すると表示されません。 このWebページでは、パスワードを初めて入力させるので、redisplay="false"を 指定しています。 なお、パスワードは通常、2回入力させておいて、それらが一致しているかどうか 検証する(画面上ではアスタリスクしか表示されないので、入力間違いがあっても 分からないため、2回入力させて検証する)のが普通ですが、ここでは省略します。 あと、<html:errors>タグを追加したことも頭に入れておいて下さい。 ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ 上記のJSPによって、新たにmembership、userid、passwordというプロパティーが 追加されましたので、これに合わせてOrderFormクラスのほうも変更しましょう。 このOrderFormクラスでは、入力データの検証も行うことにします。 では、OrderForm.javaファイルを下記のように編集して下さい。 -------------------------------------------------------- package jp.co.flsi.lecture.struts; import java.io.UnsupportedEncodingException; import javax.servlet.http.HttpServletRequest; import jp.co.flsi.lecture.reflect.ValueLogStringMaker; import org.apache.log4j.Logger; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; 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; private String membership = null; private String userid = null; private String password = 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; } public void setMembership(String membership) { this.membership = membership; } public String getMembership() { return membership; } public void setUserid(String userid) { this.userid = userid; } public String getUserid() { return userid; } public void setPassword(String password) { this.password = password; } public String getPassword() { return password; } public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { logger.info("Start ..............."); ValueLogStringMaker stringMaker = new ValueLogStringMaker(); ActionErrors errors = new ActionErrors(); try { logger.info("Method parameter: <<<<<" + stringMaker.getValues("mapping", mapping)); logger.info(">>>>>"); logger.info("Method parameter: <<<<<" + stringMaker.getValues("request", request)); logger.info(">>>>>"); if (membership.equals("yes")) { if (userid.equals("")) { errors.add("userid", new ActionMessage("errors.userid.required")); } if (password.equals("")) { errors.add("password", new ActionMessage("errors.password.required")); } } else if (membership.equals("no")) { if (name.equals("")) { errors.add("name", new ActionMessage("errors.name.required")); } if (zipcode.equals("")) { errors.add("zipcode", new ActionMessage("errors.zipcode.required")); } if (address.equals("")) { errors.add("address", new ActionMessage("errors.address.required")); } if (telNo.equals("")) { errors.add("telNo", new ActionMessage("errors.telNo.required")); } if (emailAddress.equals("")) { errors.add("emailAddress", new ActionMessage("errors.emailAddress.required")); } } else if (!membership.equals("new")) { errors.add("membership", new ActionMessage("errors.membership.mustselected")); } } catch (Throwable e) { logger.error(e, e); } finally { logger.info("End ..............."); } logger.info("Method return: <<<<<" + stringMaker.getValues("errors", errors)); logger.info(">>>>>"); return (errors); } } -------------------------------------------------------- 上のソース・コードの中で各errors.add()の第一引数が先ほどのorder.jspの中の 各<html:errors>タグのproperty属性の値に対応していることを確認して下さい。 ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ では、これらの各errors.add()の第二引数に合わせて、MessageResources.properties にメッセージを追加しておきましょう。 (1) プロジェクト・エクスプローラーのStrutsShop配下の「Javaリソース: src」配下 のMessageResources.propertiesを右クリックし、「アプリケーションから開く」→ 「Limyプロパティー・エディター」を選択します。 (2) MessageResources.propertiesのエディターが開いたら、 MessageResources.propertiesファイルの最後に次のような行を追加して下さい。 -------------------------------------------------------- errors.userid.required=ユーザーIDを入力する必要があります。 errors.password.required=パスワードを入力する必要があります。 errors.name.required=お名前を入力する必要があります。 errors.zipcode.required=郵便番号を入力する必要があります。 errors.address.required=ご住所を入力する必要があります。 errors.telNo.required=お電話番号を入力する必要があります。 errors.emailAddress.required=Eメール・アドレスを入力する必要があります。 errors.membership.mustselected=会員登録に関する項目(「会員登録済み」など)を選択する必要があります。 -------------------------------------------------------- 念のため、MessageResources.propertiesファイルの中身全体を下記に表示します。 -------------------------------------------------------- # -- standard errors -- errors.header=<font color="#ff0000"><b> errors.prefix= errors.suffix=<br><br> errors.footer=</b></font> # -- validator -- errors.invalid={0} is invalid. errors.maxlength={0} can not be greater than {1} characters. errors.minlength={0} can not be less than {1} characters. errors.range={0} is not in the range {1} through {2}. errors.required={0} is required. errors.byte={0} must be an byte. errors.date={0} is not a date. errors.double={0} must be an double. errors.float={0} must be an float. errors.integer={0} must be an integer. errors.long={0} must be an long. errors.short={0} must be an short. errors.creditcard={0} is not a valid credit card number. errors.email={0} is an invalid e-mail address. # -- other -- errors.cancel=Operation cancelled. errors.detail={0} errors.general=The process did not complete. Details should follow. errors.token=Request could not be completed. Operation is not in sequence. # -- welcome -- welcome.title=Struts Blank Application welcome.heading=Welcome! welcome.message=To get started on your own application, copy the struts-blank.war to a new WAR file using the name for your application. Place it in your container's "webapp" folder (or equivalent), and let your container auto-deploy the application. Edit the skeleton configuration files as needed, restart your container, and you are on your way! (You can find the application.properties file with this message in the /WEB-INF/src/java/resources folder.) # -- StrutsShop order -- errors.order.quantity.required=購入個数に空文字が入力されましたが、受け付けられません。 errors.order.quantity.integer=購入個数に数字以外の文字が入力されましたが、受け付けられません。 errors.userid.required=ユーザーIDを入力する必要があります。 errors.password.required=パスワードを入力する必要があります。 errors.name.required=お名前を入力する必要があります。 errors.zipcode.required=郵便番号を入力する必要があります。 errors.address.required=ご住所を入力する必要があります。 errors.telNo.required=お電話番号を入力する必要があります。 errors.emailAddress.required=Eメール・アドレスを入力する必要があります。 errors.membership.mustselected=会員登録に関する項目(「会員登録済み」など)を選択する必要があります。 -------------------------------------------------------- これらのメッセージは、vol.196に書いたように、Unicodeエスケープに変換しておく 必要がありますが、このLimyプロパティー・エディターというEclipseのプラグイン が自動的に変換してくれますので単純に保管(Ctrl + S)するだけで大丈夫です。 (プロパティー・エディター上では普通の日本語文字で表示されますがファイルの内部 はUnicodeエスケープに変換されています。) (Limyのプラグインは現在使用している「Pleiades All in One 日本語ディストリビューション」 に予めインストールされているものです。) ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ では続いて、ConfirmOrderActionクラスを編集しましょう。 ConfirmOrderAction.javaファイルを下記のように変更して下さい。 -------------------------------------------------------- package jp.co.flsi.lecture.struts; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Vector; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import jp.co.flsi.lecture.reflect.ValueLogStringMaker; import jp.co.flsi.lecture.security.PasswordEncryption; import jp.co.flsi.lecture.struts.db.Order; import jp.co.flsi.lecture.struts.db.OrderItem; import jp.co.flsi.lecture.struts.db.StruShopDbException; import jp.co.flsi.lecture.struts.db.User; import jp.co.flsi.lecture.struts.db.UserDbManager; import org.apache.log4j.Logger; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; public class ConfirmOrderAction extends Action { private static Logger logger = Logger.getLogger(ConfirmOrderAction.class); public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { logger.info("Start ..............."); UserDbManager userDbManager = new UserDbManager(); try { ValueLogStringMaker stringMaker = new ValueLogStringMaker(); logger.info("Method parameter: <<<<<" + stringMaker.getValues("mapping", mapping)); logger.info(">>>>>"); logger.info("Method parameter: <<<<<" + stringMaker.getValues("form", form)); logger.info(">>>>>"); logger.info("Method parameter: <<<<<" + stringMaker.getValues("request", request)); logger.info(">>>>>"); logger.info("Method parameter: <<<<<" + stringMaker.getValues("response", response)); logger.info(">>>>>"); HttpSession session = request.getSession(); Order anOrder = (Order)session.getAttribute("ORDER"); if (anOrder == null) { logger.info("Method return: <<<<< cartVacant (1)"); logger.info(">>>>>"); return mapping.findForward("cartVacant"); } Vector<OrderItem> orderItemList = anOrder.getOrderItems(); if (orderItemList == null) { logger.info("Method return: <<<<< cartVacant (2)"); logger.info(">>>>>"); return mapping.findForward("cartVacant"); } OrderForm orderForm = (OrderForm) form; anOrder.setPayMethod(Integer.parseInt(orderForm.getPayMethod())); // 新規に会員登録する場合: if (orderForm.getMembership().equals("new")) { logger.info("Method return: <<<<< newUser"); logger.info(">>>>>"); return mapping.findForward("newUser"); } User user = null; userDbManager.connect(); // 既に会員登録済みの場合: if (orderForm.getMembership().equals("yes")) { user = userDbManager.getDataByUserTypeAndUserid("R", orderForm.getUserid()); // (会員登録した顧客のユーザー・タイプは"R") // 入力されたユーザーIDに該当するユーザーがデータベースに見つからない場合: if (user.getUserid().equals("")) { logger.info("Method return: <<<<< useridInvalid"); logger.info(">>>>>"); return mapping.findForward("useridInvalid"); } // 入力されたパスワードが正しくない場合: if (!PasswordEncryption.checkWithEncryptedPassword(orderForm.getPassword(), user.getPassword())) { logger.info("Method return: <<<<< passwordInvalid"); logger.info(">>>>>"); return mapping.findForward("passwordInvalid"); } } else { // 会員登録せずに購入する場合: user = new User(); String maxUserid = userDbManager.getMaxTemporaryUserid(); user.setUserType("T"); // 一時的顧客のユーザー・タイプは"T" NumberFormat formatter = new DecimalFormat("0000000"); user.setUserid(formatter.format(Integer.parseInt(maxUserid) + 1)); user.setPassword(PasswordEncryption.encrypt("NONE")); user.setName(orderForm.getName()); user.setZipcode(orderForm.getZipcode()); user.setAddress(orderForm.getAddress()); user.setTelno(orderForm.getTelNo()); user.setEmail(orderForm.getEmailAddress()); if (!userDbManager.insertData(user)) { logger.info("Method return: <<<<< userInsertError"); logger.info(">>>>>"); return mapping.findForward("userInsertError"); } } anOrder.setUserType(user.getUserType()); anOrder.setUserId(user.getUserid()); session.setAttribute("USER", user); } catch (StruShopDbException e) { logger.error(e, e); } catch (Throwable e) { logger.error(e, e); } finally { try { userDbManager.disconnect(); } catch (Exception e) { logger.info("Disconnect failed or there is no connection."); } logger.info("End ..............."); } logger.info("Method return: <<<<< success"); logger.info(">>>>>"); return mapping.findForward("success"); } } -------------------------------------------------------- ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ (次回に続く) では、今日はここまでにします。 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: 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. 不許無断複製 |