Accessing the Session and Other Form Beans


Sometimes, you need to get a handle on the Session during Action processing. Fortunately, it's easy to get at. All you need to do is to use request.getSession() . After you have a handle on the session, you can use getAttribute and setAttribute to gain access to session properties.

In more complex applications, you'll commonly have several pages of input awaiting processing. For example, you could decide that the user creation page is too long and should be broken down into two pages. To do this, you would begin by dividing the JSP form into two pieces, as shown in Listings 8.3 and 8.4.

Listing 8.3 newUserName.jsp
 <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> <%@ taglib uri="/WEB-INF/struts-template.tld" prefix="tmp"%> <%@ taglib uri="/WEB-INF/stock.tld" prefix="stock"%> <tmp:insert template="header.jsp"> <tmp:put name="title">Create a New Account</tmp:put> </tmp:insert> <table width="100%" BORDER="1" CELLPADDING="5">     <TR><TD WIDTH="250" VALIGN="TOP" HALIGN="LEFT"> <tmp:insert template="minibar.jsp"/> </TD><TD VALIGN="TOP">         <html:errors property="org.apache.struts.action.GLOBAL_ERROR"/> <table>   <html:form action="/newUserName.do">   <tr>     <td colspan="2">       <h2>New User Registration (Part 1)</h2>     </td>   </tr>   <tr>     <td>username</td>     <td><html:text property="username" maxlength="15" size="15"/>     </td><td><html:errors property="username"/></td>   </tr>   <tr>     <td>password</td>     <td><html:text property="password" maxlength="15" size="15"/></td>     <td><html:errors property="password"/></td>   </tr>   <tr>     <td>email</td><td><html:text property="email" maxlength="30" size="30"/></td>     <td><html:errors property="email"/></td>   </tr>   <tr>     <td>firstName</td>     <td><html:text property="firstName" maxlength="30" size="30"/></td>     <td><html:errors property="firstName"/></td>   </tr>   <tr>     <td>lastName</td>     <td><html:text property="lastName" maxlength="30" size="30"/></td>     <td><html:errors property="lastName"/></td>   </tr>   <tr>     <td colspan="2"><html:submit property="ok"/></td>   </tr>   </html:form> </table> </TD></TR></TABLE> </body> </html> 
Listing 8.4 newUserAddress.jsp
 <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> <%@ taglib uri="/WEB-INF/struts-template.tld" prefix="tmp"%> <%@ taglib uri="/WEB-INF/stock.tld" prefix="stock"%> <tmp:insert template="header.jsp"> <tmp:put name="title">Create a New Account</tmp:put> </tmp:insert> <table width="100%" BORDER="1" CELLPADDING="5"><TR>     <TD WIDTH="250" VALIGN="TOP" HALIGN="LEFT"> <tmp:insert template="minibar.jsp"/> </TD><TD VALIGN="TOP">    <html:errors property="org.apache.struts.action.GLOBAL_ERROR"/> <table>   <html:form action="/newUserAddress.do">   <tr>     <td colspan="2">       <h2>New User Registration (Part 2)</h2>     </td>   </tr>   <tr>     <td>streetAddress1</td><td><html:text property="streetAddress1"                                      maxlength="60" size="60"/></td>     <td><html:errors property="streetAddress1"/></td>   </tr>   <tr>     <td>streetAddress2</td><td><html:text property="streetAddress2"                                      maxlength="60" size="60"/></td>     <td><html:errors property="streetAddress2"/></td>   </tr>   <tr>     <td>city</td><td><html:text property="city" maxlength="30" size="30"/></td>     <td><html:errors property="city"/></td>   </tr>   <tr>     <td>state</td><td><html:text property="state" maxlength="2" size="2"/></td>     <td><html:errors property="state"/></td>   </tr>   <tr>     <td>postalCode</td><td><html:text property="postalCode"                                  maxlength="10" size="10"/></td>     <td><html:errors property="postalCode"/></td>   </tr>   <tr>     <td>homePhone</td><td><html:text property="homePhone"                                 maxlength="13" size="13"/></td>     <td><html:errors property="homePhone"/></td>   </tr>   <tr>     <td>workPhone</td><td><html:text property="workPhone"                                 maxlength="13"size="13"/></td>     <td><html:errors property="workPhone"/></td>   </tr>   <tr>     <td>workExt</td><td><html:text property="workExt"                               maxlength="10" size="10"/></td>     <td><html:errors property="workExt"/></td>   </tr>   <tr>     <td colspan="2"><html:submit property="ok"/></td>   </tr>   </html:form> </table> </TD></TR></TABLE> </body> </html> 

These are essentially the same as before, only broken into two pieces. The actions of the forms have also been changed to newUserName.do and newUserAddress.do .

Next , the ActionForm s must also be broken in half (Listings 8.5 and 8.6).

Listing 8.5 NewUserNameForm.java
 package stocktrack.struts.form; import javax.servlet.http.*; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionForm; import stocktrack.struts.form.BaseForm; /**  * stocktrack.struts.form.NewUserNameForm class.  * this class used by Struts Framework to store data from newUserForm  *  * struts-config declaration:  * <form-bean name="newUserNameForm"  *         type="stocktrack.struts.form.NewUserNameForm" />  *  * @see org.apache.struts.action.ActionForm org.apache.struts.action.ActionForm  * Generated by StrutsWizard.  */ public class NewUserNameForm extends BaseForm {   public void reset(ActionMapping mapping, HttpServletRequest request) {     username = "";     password = "";     firstName = "";     lastName = "";   }   public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {     ActionErrors errors = new ActionErrors();     if (this.isBlankString(username)) {         errors.add("username", new ActionError("stocktrack.newuser.required"));     }     if (this.isBlankString(password)) {         errors.add("password", new ActionError("stocktrack.newuser.required"));     }     if (this.isBlankString(email)) {         errors.add("email", new ActionError("stocktrack.newuser.required"));     } else {         if (email.indexOf("@") == -1) {         errors.add("email", new ActionError("stocktrack.newuser.invalid.email"));         }     }     if (this.isBlankString(firstName)) {         errors.add("firstName", new ActionError("stocktrack.newuser.required"));     }     if (this.isBlankString(lastName)) {         errors.add("lastName", new ActionError("stocktrack.newuser.required"));     }     return errors;   }   private String username;   private String password;   private String email;   private String firstName;   private String lastName;   public String getUsername() {     return username;   }   public void setUsername(String username) {     this.username = username;   }   public String getPassword() {     return password;   }   public void setPassword(String password) {     this.password = password;   }   public String getEmail() {     return email;   }   public void setEmail(String email) {     this.email = email;   }   public String getFirstName() {     return firstName;   }   public void setFirstName(String firstName) {     this.firstName = firstName;   }   public String getLastName() {     return lastName;   }   public void setLastName(String lastName) {     this.lastName = lastName;   } } 
Listing 8.6 NewUserAddressForm.java
 package stocktrack.struts.form; import javax.servlet.http.*; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionForm; import stocktrack.struts.form.BaseForm; /**  * stocktrack.struts.form.NewUserAddressForm class.  * this class used by Struts Framework to store data from newUserAddressForm  *  * struts-config declaration:  * <form-bean name="newUserAddressForm"  *         type="stocktrack.struts.form.NewUserAddressForm" />  *  * @see org.apache.struts.action.ActionForm org.apache.struts.action.ActionForm  * Generated by StrutsWizard.  */ public class NewUserAddressForm extends BaseForm {   public void reset(ActionMapping mapping, HttpServletRequest request) {     streetAddress1 = "";     streetAddress2 = "";     city = "";     state = "";     postalCode = "";     homePhone = "";     workPhone = "";     workExt = "";   }   public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {     ActionErrors errors = new ActionErrors();     if (this.isBlankString(streetAddress1)) {         errors.add("streetAddress1",                    new ActionError("stocktrack.newuser.required"));     }     if (this.isBlankString(city)) {         errors.add("city", new ActionError("stocktrack.newuser.required"));    }     if (this.isBlankString(state)) {         errors.add("state", new ActionError("stocktrack.newuser.required"));    } else {       if (!this.isValidState(state)) {         errors.add("state", new ActionError("stocktrack.newuser.invalid.state"));       }    }      if (this.isBlankString(postalCode)) {          errors.add("postalCode", new ActionError("stocktrack.newuser.required"));      } else {        if  (!this.isValidPostalCode(postalCode)) {             errors.add("postalCode",                        new ActionError("stocktrack.newuser.invalid.postalCode"));        }     }     if (this.isBlankString(homePhone)) {         errors.add("homePhone", new ActionError("stocktrack.newuser.required"));     } else {         if (!this.isValidPhone(homePhone)) {           errors.add("homePhone",                      new ActionError("stocktrack.newuser.invalid.phone"));         }     }     if (this.isBlankString(workPhone)) {         errors.add("workPhone", new ActionError("stocktrack.newuser.required"));     } else {         if (!this.isValidPhone(workPhone)) {           errors.add("workPhone",                      new ActionError("stocktrack.newuser.invalid.phone"));         }     }     return errors;   }   private String streetAddress1;   private String streetAddress2;   private String city;   private String state;   private String postalCode;   private String homePhone;   private String workPhone;   private String workExt;   public String getStreetAddress1() {     return streetAddress1;   }   public void setStreetAddress1(String streetAddress1) {     this.streetAddress1 = streetAddress1;   }   public String getStreetAddress2() {     return streetAddress2;   }   public void setStreetAddress2(String streetAddress2) {     this.streetAddress2 = streetAddress2;   }   public String getCity() {     return city;   }   public void setCity(String city) {     this.city = city;   }   public String getState() {     return state;   }   public void setState(String state) {     this.state = state;   }   public String getPostalCode() {     return postalCode;   }   public void setPostalCode(String postalCode) {     this.postalCode = postalCode;   }   public String getHomePhone() {     return homePhone;   }   public void setHomePhone(String homePhone) {     this.homePhone = homePhone;   }   public String getWorkPhone() {     return workPhone;   }   public void setWorkPhone(String workPhone) {     this.workPhone = workPhone;   }   public String getWorkExt() {     return workExt;   }   public void setWorkExt(String workExt) {     this.workExt = workExt;   } } 

Again, you've simply split the form beans in half, and made sure that the validations validate only for the properties of the form in question.

AN ALTERNATIVE TO SPLITTING THE FORM BEAN

One of the interesting things about co-authoring a book is that sometimes the authors have two different approaches to the same problem. For example, my (James) initial impulse when breaking the form in two was to split the ActionForm bean as well.

Kevin, on the other hand, says he would have used a single ActionForm , had the validate() method check for a property called action that was set by a hidden form field in the JSP, and choose which set of fields to validate based on the value of this property. He points out that the advantage of this approach is that you can easily move fields from one form to another by just changing the validate code, and that it lets the validate code for the second form have easy access to the data from the first form (if, for example, a validation on the second page is dependent on a value set on the first).

And thus are the differences in style that make life interesting...

Finally, the interesting part of the exercise. The Action classes also are broken in two, as shown in Listings 8.7 and 8.8.

Listing 8.7 NewUserNameAction.java
 package stocktrack.struts.action; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.*; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionError; import org.apache.struts.action.Action; import stocktrack.torque.*; import stocktrack.struts.form.NewUserNameForm; /**  * stocktrack.struts.action.NewUserNameAction class.  * this class used by Struts Framework process the  * stocktrack.struts.form.NewUserForm form.  * - method invoked by HTTP request is perform(....)  * - form name is newUserNameForm  * - input page is newUserName.jsp  * - scope name is request  * - path for this action is /newusername  *  * struts-config declaration:  * <action name="newUserNameForm"  *         path="/newusername"  *         type="stocktrack.struts.action.NewUserNameAction"  *         input="newUserName.jsp"  *         scope="session"  *         validate="true" >  *            <!-- yours forwards -->  * </action>  *  * @see org.apache.struts.action.Action org.apache.struts.action.Action  * Generated by StrutsWizard.  */ public class NewUserNameAction extends org.apache.struts.action.Action {   public ActionForward perform(ActionMapping mapping, ActionForm form,                                HttpServletRequest request,                                HttpServletResponse response)              throws IOException, ServletException {         return mapping.findForward("newUserAddress");   } } 

The first Action , which handles input from the name form, simply passes control on to the second screen, which has the address fields. Because the form is of scope "session" , the form and the data it holds will be held as a session property until they're explicitly removed or the session terminates. This means that it will be available to the Action that handles the address form submission, allowing the data to be merged into a single record.

Listing 8.8 NewUserAddressAction.java
 package stocktrack.struts.action; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.*; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionError; import org.apache.struts.action.Action; import stocktrack.torque.*; import stocktrack.struts.form.NewUserNameForm; import stocktrack.struts.form.NewUserAddressForm; /**  * stocktrack.struts.action.NewUserAddressAction class.  * this class used by Struts Framework process the  * stocktrack.struts.form.NewUserForm form.  * - method invoked by HTTP request is perform(....)  * - form name is newUserAddressForm  * - input page is newUserAddress.jsp  * - scope name is request  * - path for this action is /newusername  *  * struts-config declaration:  * <action name="newUserAddressForm"  *         path="/newuseraddress"  *         type="stocktrack.struts.action.NewUserAddressAction"  *         input="newUserAddress.jsp"  *         scope="session"  *         validate="true" >  *            <!-- yours forwards -->  * </action>  *  * @see org.apache.struts.action.Action org.apache.struts.action.Action  * Generated by StrutsWizard.  */ public class NewUserAddressAction extends org.apache.struts.action.Action {   public ActionForward perform(ActionMapping mapping,                                ActionForm form,                                HttpServletRequest request,                                HttpServletResponse response)                   throws IOException, ServletException {       NewUserAddressForm uf = (NewUserAddressForm) form;       NewUserNameForm nf =         (NewUserNameForm) request.getSession().getAttribute("newUserNameForm");       if (nf == null) return mapping.findForward("newUserName");       try {         User u = UserPeer.findUserByUsername(nf.getUsername());         if (u != null) {           ActionErrors errors = new ActionErrors();           errors.add(ActionErrors.GLOBAL_ERROR,                      new ActionError("stocktrack.newuser.duplicate.user"));           this.saveErrors(request, errors);           return mapping.findForward("newUserName");         }         u = new User();         u.setUserEmailAddress(nf.getEmail());         u.setUserFirstName(nf.getFirstName());         u.setUserLastName(nf.getLastName());         u.setUserPassword(nf.getPassword());         u.setUserUsername(nf.getUsername());         Address a = new Address();         a.setAddressStreet1(uf.getStreetAddress1());         a.setAddressStreet2(uf.getStreetAddress2());         a.setAddressCity(uf.getCity());         a.setAddressState(uf.getState());         a.setAddressPostalCode(uf.getPostalCode());         a.setAddressWorkPhone(uf.getWorkPhone());         a.setAddressWorkExt(uf.getWorkExt());         a.setAddressHomePhone(uf.getHomePhone());         a.save();         u.setAddress(a);         u.save();         request.getSession().setAttribute(stocktrack.Constants.VALIDATED_USER, u);         request.getSession().setAttribute("newUserNameForm", null);         request.getSession().setAttribute("newUserAddressForm", null);         return mapping.findForward("home");       }       catch (Exception ex) {         ex.printStackTrace();         return mapping.findForward("error");       }   } } 

The Action for the address form is much meatier. First, it checks to make sure that there has been a name form filled out. The name form was defined in struts-config.xml to have session scope, which means that it was stored in the session object as an attribute. The attribute name is the name of the form as defined in the Struts configuration.

In other words, unlike your previous forms, which kept the ActionForm around only long enough to get it back to the JSP form if there was a validation error (or to the Action if it was valid), you'll now keep the contents of the form around as a session property until it is explicitly removed.

You need to check whether the property is there because someone could conceivably type the URL for the second form into the browser (or bookmark it), which will cause problems when the code looks for those form values. If the property isn't there, the Controller is told to send the user over to the first page of the form.

Next, the check for duplicate users is made. Because the browser just came from the address form but the username is on the name form, the controller must redirect flow back to the name form. For that reason, an explicit findForward is used rather than a getInputForward .

The only other difference between the remainder of this code and the original Action class is that this class needs to take input from two different ActionForm s to populate the model. Also, after the form successfully submits, the session properties for the two forms are set to null so that none of the data will appear the next time the forms are used. (Alternatively, you could call the reset methods on both forms, which would also clear the data out.)

Figures 8.1 and 8.2 show this new pair of forms in operation. From the user's perspective, the only difference is that there are now two forms instead of a single one.

Figure 8.1. Submitting data to newUserName.jsp .

graphics/08fig01.gif

Figure 8.2. The second part of creating a user, newUserAddress.jsp .

graphics/08fig02.gif



Struts Kick Start
Struts Kick Start
ISBN: 0672324725
EAN: 2147483647
Year: 2002
Pages: 177

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