Credit Cards and the Wallet

I l @ ve RuBoard

Now that you have addresses, you can write the wallet. A lot of the credit card code (see Listing 11.11) is very similar to the address code. I'm just going to discuss the areas that are different.

Listing 11.11 CreditCard.java
 package com.bfg.customer; import java.util.Vector; import java.util.HashMap; import java.util.Iterator; import org.apache.turbine.services.db.TurbineDB; import org.apache.turbine.util.db.pool.DBConnection; import org.apache.turbine.util.TurbineConfig; import com.bfg.exceptions.CustomerActivityException; import java.sql.*; import java.util.ResourceBundle; import org.apache.log4j.Category; import javax.naming.NamingException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingEnumeration; import javax.naming.directory.InitialDirContext; import java.text.SimpleDateFormat; import java.text.ParseException; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Date; public class CreditCard {     static Category cat = Category.getInstance(CreditCard.class);     private static ResourceBundle sql_bundle =      ResourceBundle.getBundle("com.bfg.customer.SQLQueries");     protected int cardID;     protected Address address;     protected Customer customer;     protected String cardOwner;     protected String cardType;     protected String cardNumber;     protected int expMonth;     protected int expYear;     public int getCardID() {      return cardID;     }     public void setCardID(int id) {      cardID = id;     }     public Address getAddress() {      return address;     }     public void setAddress(Address addr) {      address = addr;     }     public Customer getCustomer() {      return customer;     }     public void setCustomer(Customer cust) {      customer = cust;     }     public String getCardOwner() {      return cardOwner;     }     public void setCardOwner(String name) {      cardOwner = name;     }     public String getCardType() {      return cardType;     }     public void setCardType(String name) {      cardType = name;     }     public String getCardNumber () {      return cardNumber;     }     public String getObscuredNumber () {      if ((cardNumber != null) &&          (cardNumber.length() > 6)) {          String digitsOnly = getDigitsOnly(cardNumber);          String allStars = "****************************************";          return digitsOnly.substring(0,2) +              allStars.substring(0, digitsOnly.length() - 6) +              digitsOnly.substring(digitsOnly.length() - 4,                                    digitsOnly.length());      }  else {           return "";      }     }     public void setCardNumber(String name) {      cardNumber = name;     }     public int getExpMonth () {      return expMonth;     }     public void setExpMonth(int month) {      expMonth = month;     }     public int getExpYear () {      return expYear;     }     public void setExpYear(int year) {      expYear = year;     }     private HashMap validationErrors = new HashMap();     public String getFieldError(String fieldname) {      return((String)validationErrors.get(fieldname));     }     public void addFieldError(String fieldname, String error) {      validationErrors.put(fieldname, error);     }     public boolean validateCCDate(int expMonth, int expYear) {      SimpleDateFormat formatter = new SimpleDateFormat ("MM/yy");      try {          GregorianCalendar c =  new GregorianCalendar();          c.setTime(formatter.parse(expMonth + "/" + expYear));          c.roll(Calendar.MONTH, 1);          c.set(Calendar.DATE, 1);          c.set(Calendar.HOUR, 0);          c.set(Calendar.MINUTE, 0);          c.set(Calendar.SECOND, 0);          Date now = new Date();          return (now.compareTo(c.getTime()) < 0);      }  catch (ParseException ex) {} ;      return false;     }     private String getDigitsOnly (String s) {      StringBuffer digitsOnly = new StringBuffer ();      char c;      for (int i = 0; i < s.length (); i++) {          c = s.charAt (i);          if (Character.isDigit (c)) {              digitsOnly.append (c);          }      }      return digitsOnly.toString ();     }     public boolean validateCreditCardNumber (String cardNumber) {      String digitsOnly = getDigitsOnly (cardNumber);      int sum = 0;      int digit = 0;      int addend = 0;      boolean timesTwo = false;      int digitLength = digitsOnly.length();      boolean foundcard = false;      // MC      if (digitsOnly.startsWith("51")  digitsOnly.startsWith("52")           digitsOnly.startsWith("53")  digitsOnly.startsWith("54")) {          if (digitLength != 16) return false;          foundcard = true;      }      // VISA      if (digitsOnly.startsWith("4")) {          if ((digitLength != 16) && (digitLength != 13)) return false;          foundcard = true;      }      // AMEX      if (digitsOnly.startsWith("34")  digitsOnly.startsWith("37")) {          if (digitLength != 15) return false;          foundcard = true;      }      // DISC      if (digitsOnly.startsWith("6011")) {          if (digitLength != 16) return false;          foundcard = true;      }      if (!foundcard) return false;      for (int i = digitsOnly.length () - 1; i >= 0; i) {          digit = Integer.parseInt (digitsOnly.substring (i, i + 1));          if (timesTwo) {              addend = digit * 2;              if (addend > 9) {                  addend -= 9;              }          }          else {             addend = digit;          }          sum += addend;          timesTwo = !timesTwo;      }      int modulus = sum % 10;      return modulus == 0;     }     public boolean validateCreditCard() {      validationErrors.clear();      boolean valid = true;      if ((cardType == null)           (cardType.length() == 0)) {          addFieldError("cardType", "Card Type is required.");          valid = false;      }      if ((cardOwner == null)           (cardOwner.length() == 0)) {          addFieldError("cardOwner", "Cardholder Name is required.");          valid = false;      }      if ((cardNumber == null)           (cardNumber.length() == 0)) {          addFieldError("cardNumber", "Card Number is required.");          valid = false;      }   else {          if (!validateCreditCardNumber(cardNumber)) {           addFieldError("cardNumber", "Invalid Card Number");           valid = false;          }      }      if (expMonth == 0) {          addFieldError("expMonth", "Expiration Month is required.");          valid = false;      }      if (expYear == 0) {          addFieldError("expYear", "Expiration Year is required.");          valid = false;      }      if (!validateCCDate(expMonth, expYear)) {          addFieldError("expYear", "Expired Card Date");          valid = false;      }      return valid;     }     public static CreditCard findCreditCard(int cardID)      throws CustomerActivityException {      CreditCard cc = null;          DBConnection dbConn = null;          try              {                  dbConn = TurbineDB.getConnection();                  if (dbConn == null) {                      cat.error("Can't get database connection");                      throw new CustomerActivityException();                  }                  PreparedStatement pstmt =                      dbConn.prepareStatement(sql_bundle.getString("creditQuery"));                  pstmt.setInt(1, cardID);                  ResultSet rs = pstmt.executeQuery();                  if (rs.next()) {                      cc = new CreditCard();                      cc.setCardType(rs.getString("CARD_TYPE"));                      cc.setCardNumber(rs.getString("CARD_NUMBER"));                      cc.setCardOwner(rs.getString("CARD_OWNERNAME"));                      cc.setExpMonth(rs.getInt("CARD_EXPMONTH"));                      cc.setExpYear(rs.getInt("CARD_EXPYEAR"));                      cc.setAddress(Address.findAddress(rs.getInt("ADDRESS_KEY"))); cc.setCustomer(Customer.findCustomer(rs.getString("EMAIL_ADDRESS")));                  }  else {                       cat.error("Couldn't find record for Credit Card");                  }                  rs.close();                  pstmt.close();               }           catch (Exception e)               {                   cat.error("Error during findCreditCard", e);                   throw new CustomerActivityException();               }           finally               {                   try                        {                           TurbineDB.releaseConnection(dbConn);             }     catch (Exception e)         {             cat.error("Error during release connection", e);             } }         return cc;      }     public void createCreditCard()      throws CustomerActivityException {          DBConnection dbConn = null;          try              {                  dbConn = TurbineDB.getConnection();                  if (dbConn == null) {                      cat.error("Can't get database connection");                      throw new CustomerActivityException();                  }                  PreparedStatement pstmt =                      dbConn.prepareStatement(sql_bundle.getString("creditInsert"));                  pstmt.setInt(1, getCustomer().getCustomerId());                  pstmt.setString(2, getCardType());                  pstmt.setString(3, getCardNumber());                  pstmt.setString(4, getCardOwner());                  pstmt.setInt(5, getExpMonth());                  pstmt.setInt(6, getExpYear());                  pstmt.setInt(7, getAddress().getAddressID());                  pstmt.executeUpdate();                  pstmt.close();                  pstmt =                       dbConn.prepareStatement(sql_bundle.getString("addressID"));                  ResultSet rs = pstmt.executeQuery();                  if (rs.next()) {                       setCardID(rs.getInt(1));                  }  else {                       cat.error("Couldn't find record for new Credit Card");                  }                  rs.close();                  pstmt.close();               }           catch (Exception e)               {                   cat.error("Error during createCreditCard", e);                   throw new CustomerActivityException();               }           finally               {                   try                       {                           TurbineDB.releaseConnection(dbConn);                       }                   catch (Exception e)                       {                          cat.error("Error during release connection", e);                       }               }      }     public void updateCreditCard()      throws CustomerActivityException {         DBConnection dbConn = null;         try              {                 dbConn = TurbineDB.getConnection();                 if (dbConn == null) {                     cat.error("Can't get database connection");                     throw new CustomerActivityException();                 }                 PreparedStatement pstmt =                      dbConn.prepareStatement(sql_bundle.getString("cardUpdate"));                 pstmt.setInt(1, getCustomer().getCustomerId());                 pstmt.setString(2, getCardType());                 pstmt.setString(3, getCardNumber());                 pstmt.setString(4, getCardOwner());                 pstmt.setInt(5, getExpMonth());                 pstmt.setInt(6, getExpYear());                 pstmt.setInt(7, getAddress().getAddressID());                 pstmt.setInt(8, getCardID());                 pstmt.executeUpdate();                 pstmt.close();               }           catch (Exception e)               {                   cat.error("Error during updateCreditCard", e);                   throw new CustomerActivityException();               }           finally               {                   try                       {                           TurbineDB.releaseConnection(dbConn);                       }                   catch (Exception e)                       {                           cat.error("Error during release connection", e);                       }               }      }     public void deleteCreditCard()      throws CustomerActivityException {          DBConnection dbConn = null;          try               {                  dbConn = TurbineDB.getConnection();                  if (dbConn == null) {                      cat.error("Can't get database connection");                      throw new CustomerActivityException();                  }                  getAddress().deleteAddress();                  PreparedStatement pstmt =                      dbConn.prepareStatement(sql_bundle.getString("credit Delete"));                  pstmt.setInt(1, getCardID());                  pstmt.executeUpdate();                  pstmt.close();               }           catch (Exception e)               {                   cat.error("Error during deleteCreditCard", e);                   throw new CustomerActivityException();         }     finally         {           try               {                   TurbineDB.releaseConnection(dbConn);               }           catch (Exception e)               {                   cat.error("Error during release connection", e);               }           }     } } 

The getObscuredNumber method is used to return the credit card number with everything but the first two and last four digits obscured.

At last, you have some interesting validations! First off, the code must make sure that it hasn't been handed an expired credit card. Working with dates in Java can seem a bit annoying at times because each of the various ways of representing time ( Time , Date , and Calendar ) has certain operations that it supports and certain ones that it doesn't. You might need to convert back and forth several times to get the final result. This code is one of several ways to find out whether a card is expired. It sets the calendar to the first second of the following month and checks whether today's date is greater than it ”a card that expires on 10/02 really expires at midnight of 10/31/02.

If you wanted to internationalize the application, you would use resource bundles instead of the hard-wired error strings here so that locale-dependent messages can be returned.

You will also want to prevalidate the card number. This code will do a number of checks:

  • Check to make sure that the prefix (the first one or two digits of the card) is valid.

  • Check to make sure that the number of digits is appropriate for the card type.

  • Use the industry checksum to make sure that the card is likely to be a valid one.

WHY PREVALIDATE?

Because you're eventually going to hand off the credit card to a third party for authorization, why prevalidate the card number?

First, card validation is a slow process involving a network transaction that can take from several seconds to a minute or more. So, it is much better to catch the simple errors that you can with a simple set of tests.

Second, authorization is the last thing that you do before recording the order. It will be difficult to navigate the user back to an editing screen to fix the number. So again, it's better to catch it early.

Interestingly, because you can determine the credit card type from the card number prefix, there's really no reason to request the card type explicitly, but consumers seem to expect it.

Because an ADDRESS record is being used to store the billing address for the credit card, the code needs to read in the Address object when it gets a credit card from the database.

Because the class needs the Address ID when it creates a new credit card, you'll need to have the code create the Address object first, set the credit card's Address field to it, and then call createCreditCard .

Adding Wallet Support to Customer

Now add the wallet support to Customer.java (see Listing 11.12), immediately following the code that you added to read in the address book in findCustomer . It's interesting to note that two different approaches were taken with addresses and credit cards. Because addresses are pointed to by both customers and credit cards, an xref table was used to associate them with customers. Because credit cards belong directly to customers, you could "hard-wire" the customer ID directly in the credit card record. That way Customer.java doesn't need a function to add and remove credit cards.

Listing 11.12 More Changes to Customer.java
 pstmt = dbConn.prepareStatement(sql_bundle.getString("getWallet")); pstmt.setInt(1, cust.getCustomerId()); rs = pstmt.executeQuery(); while (rs.next()) {     CreditCard cc = CreditCard.findCreditCard(rs.getInt(1));     cust.wallet.put(new Integer(cc.getCardID()), cc); } rs.close(); pstmt.close(); 

Now it's time to write the JSP. The MyAccount code (in Listing 11.13) is a clone of the code for the address book (in Listing 11.9).

Listing 11.13 Adding Credit Cards to MyAccount.jsp
 <center><h2>Credit Cards</h2></center> <A HREF="NewCreditCard.jsp">Add New Card</A> <% if (customer.getWallet().size() > 0) { %> <TABLE WIDTH="100%">   <TR><TH>Cardholder</TH><TH>Card Number</TH><TH>Edit</TH><TH>Delete</TH></TR> <% Iterator it = customer.getWallet().keySet().iterator(); while (it.hasNext()) {     CreditCard cc = (CreditCard) customer.getWallet().get(it.next()); %>      <TR><TD><%= cc.getCardOwner() %> </TD>          <TD><%= cc.getObscuredNumber() %></TD>          <TD><A HREF="NewCreditCard.jsp?operation=update&cardId=<%= cc.getCardID() %>">X</ graphics/ccc.gif A></TD>          <TD><A HREF="DeleteAddress.jsp?cardId=<%= cc.getCardID() %>" graphics/ccc.gif TARGET="tempwindow">X</A></TD></TR> <% }  %> </TABLE> <% }  %> 

The NewCreditCard.jsp (in Listing 11.14) code needs all the code that NewAddress.jsp had (because it needs to record the address), plus additional code to handle the credit card “specific data. It would be nice if you could somehow include the address code rather than duplicate it, but it is not worth the effort in this case ”there's only a single reuse of the code, and making the address code general would involve some heavy rewrites.

Listing 11.14 NewCreditCard.jsp
 <%@ include file="/jsp/cust/AutoLogin.jsp" %> <%@ page import="com.bfg.customer.Customer" %> <%@ page import="com.bfg.customer.Address" %> <%@ page import="com.bfg.customer.CreditCard" %> <%@ page import="java.text.NumberFormat" %> <jsp:useBean id="customer" class="com.bfg.customer.Customer" scope="session"/> <jsp:useBean id="newaddr" class="com.bfg.customer.Address" scope="request"/> <jsp:useBean id="newcredit" class="com.bfg.customer.CreditCard" scope="request"/> <% if (customer.getEmail() == null) {     response.sendRedirect("Login.jsp");     return; } %> <jsp:setProperty name="newaddr" property="*"/> <jsp:setProperty name="newcredit" property="*"/> <% NumberFormat nf = NumberFormat.getInstance(); String operation = request.getParameter("operation"); if (operation == null) {     operation = "create"; } String cardId = request.getParameter("cardId"); Integer id = null; if (!operation.equals("update")) {     newcredit.setCardNumber(request.getParameter("newCardNumber")); }  else {     if ((cardId != null) && (cardId.length() > 0)) {      try {          Number num = nf.parse(request.getParameter("cardId"));          id = new Integer(num.intValue());      }  catch (Exception e) {          response.sendRedirect("general_error.jsp");          return;      }     }     CreditCard c = (CreditCard) customer.getWallet().get(id);     if (c.getObscuredNumber().equals(request.getParameter("newCardNumber"))) {      newcredit.setCardNumber(c.getCardNumber());     }  else {     newcredit.setCardNumber(request.getParameter("newCardNumber"));     } } if (request.getParameter("SUBMITTED") != null) {     if (newcredit.validateCreditCard() && newaddr.validateAddress()) {      if (operation.equals("update")) {          CreditCard cc = (CreditCard) customer.getWallet().get(id);          if (cc != null) {              newcredit.setCustomer(customer);              newcredit.setCardID(id.intValue());              newcredit.setAddress(newaddr);              newcredit.setCustomer(customer);              newaddr.setAddressID(cc.getAddress().getAddressID());              newaddr.updateAddress();              newcredit.updateCreditCard();              customer.getWallet().put(id, newcredit);              response.sendRedirect("MyAccount.jsp");              return;         }  else {              response.sendRedirect("noaccess.jsp");              return;         }     }     else {         newaddr.createAddress();         newcredit.setAddress(newaddr);         newcredit.setCustomer(customer);         newcredit.createCreditCard();         customer.getWallet().put(new Integer(newcredit.getCardID()),                                   newcredit);         response.sendRedirect("MyAccount.jsp");         return;      }     } }  else {     if (operation.equals("update")) {      CreditCard card = (CreditCard) customer.getWallet().get(id);      if (card != null) {         newcredit = card;         newaddr = card.getAddress();      }     } } if (newaddr.getLastName() == null) {     newaddr.setLastName(""); } if (newaddr.getFirstName() == null) {     newaddr.setFirstName(""); } if (newaddr.getStreet1() == null) {     newaddr.setStreet1(""); } if (newaddr.getStreet2() == null) {     newaddr.setStreet2(""); } if (newaddr.getCity() == null) {     newaddr.setCity(""); } if (newaddr.getState() == null) {     newaddr.setState(""); } if (newaddr.getPostalCode() == null) {     newaddr.setPostalCode(""); } if (newcredit.getCardOwner() == null) {     newcredit.setCardOwner(""); } if (newcredit.getCardType() == null) {     newcredit.setCardType(""); } if (newcredit.getCardNumber() == null) {     newcredit.setCardNumber(""); } %> <% if (operation.equals("update")) { %> <HEAD><TITLE>Edit Credit Card</TITLE></HEAD><BODY> <%     }  else {%> <HEAD><TITLE>Create Credit Card</TITLE></HEAD><BODY> <% }  %> <%@ include file="/jsp/includes/bfgheader.jsp" %> <% if (operation.equals("update")) { %> <CENTER><H1>Edit Credit Card</H1></CENTER> <%     }  else {%> <CENTER><H1>Create New Credit Card</H1></CENTER> <% }  %> <FORM METHOD=POST ACTION="NewCreditCard.jsp"> <INPUT TYPE="HIDDEN" NAME="SUBMITTED" VALUE="T"> <INPUT TYPE="HIDDEN" NAME="operation" VALUE="<%= operation %>"> <INPUT TYPE="HIDDEN" NAME="cardId" VALUE="<%= request.getParameter("cardId") %>"> <% if (newcredit.getFieldError("cardOwner") != null) { %> <FONT COLOR="#FF0000"><%= newcredit.getFieldError("cardOwner")%></FONT><BR> <% }  %> Name on Card: <INPUT NAME="cardOwner" TYPE="TEXT" SIZE=50        VALUE="<%= newcredit.getCardOwner() %>"><BR> <% if  (newcredit.getFieldError("cardType") != null) { %> <FONT COLOR="#FF0000"><%= newcredit.getFieldError("cardType")%></FONT><BR> <% }  %> Card Type: <SELECT NAME="cardType"> <OPTION VALUE="">-SELECT- <OPTION VALUE="VISA"     <%= (newcredit.getCardType().equals("VISA"))?" SELECTED":"" %>>Visa <OPTION VALUE="MC"     <%= (newcredit.getCardType().equals("MC"))?" SELECTED":"" %>>MasterCard <OPTION VALUE="AMEX"     <%= (newcredit.getCardType().equals("AMEX"))?" SELECTED":"" %>>American Express <OPTION VALUE="DISC"     <%= (newcredit.getCardType().equals("DISC"))?" SELECTED":"" %>>Discover </SELECT><BR> <% if (newcredit.getFieldError("cardNumber") != null) { %> <FONT COLOR="#FF0000"><%= newcredit.getFieldError("cardNumber")%></FONT><BR> <% }  %> <% if (newcredit.getFieldError("expMonth") != null) { %> <FONT COLOR="#FF0000"><%= newcredit.getFieldError("expMonth")%></FONT><BR> <% }  %> <% if  (newcredit.getFieldError("expYear") != null) { %> <FONT COLOR="#FF0000"><%= newcredit.getFieldError("expYear")%></FONT><BR> <% } int expMonth = newcredit.getExpMonth(); int expYear = newcredit.getExpYear(); %> Card Number: <INPUT NAME="newCardNumber" TYPE="TEXT" SIZE=25        VALUE="<%= operation.equals("update")?newcredit.getObscuredNumber():newcredit.getCardNumber() %>"><BR> Expires: <SELECT NAME="expMonth">   <OPTION VALUE="">SELECT   <OPTION VALUE="1" <%= (expMonth == 1)?" SELECTED":"" %>>Jan   <OPTION VALUE="2" <%= (expMonth == 2)?" SELECTED":"" %>>Feb   <OPTION VALUE="3" <%= (expMonth == 3)?" SELECTED":"" %>>Mar   <OPTION VALUE="4" <%= (expMonth == 4)?" SELECTED":"" %>>Apr   <OPTION VALUE="5" <%= (expMonth == 5)?" SELECTED":"" %>>May   <OPTION VALUE="6" <%= (expMonth == 6)?" SELECTED":"" %>>Jun   <OPTION VALUE="7" <%= (expMonth == 7)?" SELECTED":"" %>>Jul   <OPTION VALUE="8" <%= (expMonth == 8)?" SELECTED":"" %>>Aug   <OPTION VALUE="9" <%= (expMonth == 9)?" SELECTED":"" %>>Sep   <OPTION VALUE="10" <%= (expMonth == 10)?" SELECTED":"" %>>Oct   <OPTION VALUE="11" <%= (expMonth == 11)?" SELECTED":"" %>>Nov   <OPTION VALUE="12" <%= (expMonth == 12)?" SELECTED":"" %>>Dec </SELECT> / <SELECT NAME="expYear">   <OPTION VALUE="">SELECT   <OPTION VALUE="2002" <%= (expYear == 2002)?" SELECTED":"" %>>02   <OPTION VALUE="2003" <%= (expYear == 2003)?" SELECTED":"" %>>03   <OPTION VALUE="2004" <%= (expYear == 2004)?" SELECTED":"" %>>04   <OPTION VALUE="2005" <%= (expYear == 2005)?" SELECTED":"" %>>05   <OPTION VALUE="2006" <%= (expYear == 2006)?" SELECTED":"" %>>06   <OPTION VALUE="2007" <%= (expYear == 2007)?" SELECTED":"" %>>07   <OPTION VALUE="2008" <%= (expYear == 2008)?" SELECTED":"" %>>08   <OPTION VALUE="2009" <%= (expYear == 2009)?" SELECTED":"" %>>09   <OPTION VALUE="2010" <%= (expYear == 2010)?" SELECTED":"" %>>10   <OPTION VALUE="2011" <%= (expYear == 2011)?" SELECTED":"" %>>11   <OPTION VALUE="2012" <%= (expYear == 2012)?" SELECTED":"" %>>12<P> </SELECT> <H2>Billing Address</H2><P> <% if (newaddr.getFieldError("firstName") != null) { %> <FONT COLOR="#FF0000"><%= newaddr.getFieldError("firstName")%></FONT><BR> <% }  %> <% if (newaddr.getFieldError("lastName") != null) { %> <FONT COLOR="#FF0000"><%= newaddr.getFieldError("lastName")%></FONT><BR> <% }  %> First Name: <INPUT NAME="firstName" TYPE="TEXT" SIZE=30        VALUE="<%= newaddr.getFirstName() %>"> Last Name: <INPUT NAME="lastName" TYPE="TEXT" SIZE=40        VALUE="<%= newaddr.getLastName() %>"><BR> <% if (newaddr.getFieldError("street1") != null) { %> <FONT COLOR="#FF0000"><%= newaddr.getFieldError("street1")%></FONT><BR> <% }  %> Street Addr 1: <INPUT NAME="street1" TYPE="TEXT" SIZE=80        VALUE="<%= newaddr.getStreet1() %>"><BR> Street Addr 2: <INPUT NAME="street2" TYPE="TEXT" SIZE=80        VALUE="<%= newaddr.getStreet2() %>"><BR> <% if (newaddr.getFieldError("city") != null) { %> <FONT COLOR="#FF0000"><%= newaddr.getFieldError("city")%></FONT><BR> <% }  %> <% if (newaddr.getFieldError("state") != null) { %> <FONT COLOR="#FF0000"><%= newaddr.getFieldError("state")%></FONT><BR> <% }  %> <% if  (newaddr.getFieldError("postalCode") != null) { %> <FONT COLOR="#FF0000"><%= newaddr.getFieldError("postalCode")%></FONT><BR> <% }  %> City: <INPUT NAME="city" TYPE="TEXT" SIZE=50        VALUE="<%= newaddr.getCity() %>"> State: <INPUT NAME="state" TYPE="TEXT" SIZE=2        VALUE="<%= newaddr.getState() %>"> Postal Code: <INPUT NAME="postalCode" TYPE="TEXT" SIZE=10        VALUE="<%= newaddr.getPostalCode() %>"><BR> <INPUT TYPE=SUBMIT> </FORM> <%@ include file="/jsp/includes/bfgfooter.jsp" %> 

You'll be using some tricky code with the credit card number to avoid displaying it to the customer. This is so that if someone gains unauthorized access to the account, they can't view credit card numbers that already have been entered. Because of this, don't use setProperties to set the credit card from the form submit; hand it in as a property called newCardNumber .

If the page is not doing an update, the credit card number must be new. So, just set the bean's copy to the copy from the form submit. If the page is doing an update, it checks to see if the submitted card number is equal to the "obscured" version. If it is, the page gets the real card number and puts it in the newcredit bean.

Again, the code to update the database is basically the same as the code for addresses, but now it needs to write out both a new or modified address record and a new or modified credit card record.

If you have pull-down menus in your forms and you want them to come up with the previous value, you have to end up writing some cumbersome code to put a SELECTED tag on the appropriate value. I'm a fan of the boolean?trueval:falseval Java shorthand for these kinds of things.

You need to have the code hide the card information when it displays it in the form. If the page is in an update, it places the obscured version of the card number in the form. If the customer doesn't change it, the code will match it up when the customer submits it and will replace it with the real credit card number before writing it to the database. If the customer does change it, the page will take the value entered.

Figure 11.4. NewCreditCard.jsp

graphics/11fig04.jpg

With credit card support in place, you can now create and edit your wallet to your heart's content.

TESTING CREDIT CARDS

Because you are prevalidating card numbers, you can't just type any value into the form and have it succeed. If you've done enough e-commerce work, you'll have memorized the valid test credit card numbers for each card issuer. These are numbers with the right numbers of digits and the right prefix ”and numbers that pass the checksum algorithm. They are (as of this writing):

Visa: 4111 1111 1111 1111

MasterCard: 5500 0000 0000 0004

American Express: 340000000000009

Discover: 6011000000000004

Now, while these numbers will pass your primitive prevalidation routine, they're certain not to get by a real credit card authorization check, so don't get any ideas about picking up a Porsche using one of them!

We'll talk more about credit cards and authorization in Chapter 12, "Implementing Business Logic."

Figure 11.5. MyAccount.jsp with credit cards.

graphics/11fig05.jpg

I l @ ve RuBoard


MySQL and JSP Web Applications. Data-Driven Programming Using Tomcat and MySQL
MySQL and JSP Web Applications: Data-Driven Programming Using Tomcat and MySQL
ISBN: 0672323095
EAN: 2147483647
Year: 2002
Pages: 203
Authors: James Turner

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net