Now look at the contents of index.jsp. This page uses the Struts tag logic:redirect and its forward attribute to look up the page to which visitors to this URL are to be redirected. Struts gets this information from the struts-config.xml file. Here is the global-forwards element from that file.
For the forward named welcome, the browser is to be redirected to the page at login.jsp. (Unless otherwise stated, all JSPs are stored in bball/pages.) Note that despite the use of the attribute name forward, the logic:redirect tag does a true redirect, which responds to the URL request with a message to the browser to make a new request to the redirected page. If a true forward had occurred, the browser would not have been involved, and the original request would have been directly sent to another resource on the server.
Note the Struts html:form tag and the html:text tags within its body. These render the part of the page that puts up the input fields for the user to enter. Note the property attribute of the html:text tag. These name properties of a Javabean that will hold the user name and password strings entered by the user. Recall that a Javabean is just a Java object that follows certain conventions for naming the accessor and mutator methods of its instance fields. In this case there are two fields called userName and password, and their access methods are called getUserName(), setUserName(), getPassword(), and setPassword(). Struts calls these beans form beans.
Struts will set the properties of the form bean in this example when the user submits the form. How does Struts know which bean the property attribute of the html:text tag is accessing?
Note first the input attribute of the action subelement, which specifies the page containing the input form. Note also the name attribute, which names the form bean whose properties the html:text tags access. Now Struts knows the name of the form bean - "loginForm" - to associate with the login page, but how is the class that actually implements the bean defined?
Here, the type attribute gives the Java class of the loginForm bean. Struts will find the class LoginForm in the form package located under WEB-INF/classes. This class must subclass the Struts framework's ActionForm class and may override a number of methods. Here is the definition of the LoginForm class.
Note that this class provides the required accessor and mutator methods that make it a Javabean. It also overrides the reset() and validate() methods. reset() is called by Struts whenever the login page is requested; it simply blanks out the input text fields. The validate() method is called when a user submits the page. It is intended to check that the form has simply been filled out properly; it does not do any user authentication. Here, the method merely checks that neither field is blank. Note that this check makes use of an ActionErrors object and a message resource bundle.
Note that these properties are accessible from JSP pages. Here is the full basketball login page login.jsp.
Several Struts tags in this page (bean:message and html:img) refer to properties in the resource bundle file, for example:
<li>The {0} is required for login</li>is an HTML list item that will be returned as part of the ActionError object. It takes an argument, specified by "{0}", whose value is found in the second parameter to the ActionError constructor. In this case it is the label of the field that the user failed to fill in. So, if the user did not provide the user name, the string returned in the ActionError will be:
<li>The User Name is required for login</li>How does Struts know that when a validation error occurs the login page should be redisplayed? Recall the login action element that links the basketball login page with a form bean.
Since the validate attribute is set to true, if the form bean's validate() method returns any errors, Struts will forward control back to the resource indicated by the input attribute, in this case the login page.
And how does the login page access the error messages? Recall that the page login.jsp is associated with the loginForm bean. The Struts tag html:errors accesses the bean and any ActionErrors that have been set for it. Here again is the login form, this time emphasizing the beginning of the form where any errors appear.
The html:errors tag renders a list in the form containing the text of any errors.
So, what happens if there are no validation errors? Then instead of forwarding to the login page, Struts passes control to an Action class object.
Here is a diagram showing the relationships of the login page, the form bean, and the login action:
Here is the definition of the LoginAction class. Note that the execute() method uses the form bean passed to it and attempts to authenticate the user using classes and interfaces written for the application in the service and view packages included under WEB-INF/classes (see the SecurityService and UserView classes). In this case authentication is trivial, looking for user name "123" and password "456", but a real application would look up user permissions in a database.
Struts knows what to do with an InvalidLoginException through the global-exceptions element in struts-config.xml. This element specifies the property name (attribute key) under which to find an error message in the resource bundle.
Recall yet again the login action element. It contains named forward subelements. Struts builds ActionForward objects associated with each and stores them in the ActionMapping object passed to execute(), which can access them by name using the findForward() method. In our example, execute() always returns a forward associated with success. That forward passes control to a showoptions action. Here is a diagram showing that passing of control, among other things:
Here is the showoptions action element from struts-config.xml. Ultimately, this action will result in a page (options.jsp) allowing the user to choose a basketball database option, but first those options must be created. This is done by the execute() method in the ShowOptionsAction class.
This action differs from the login action in that the form bean passed to it (optionsForm) is used to set rather than get bean properties. Specifically, the options "Add Team" and "Add Player" are placed on a list, which is made the value of the options property on the form bean. However, in this case the class of the form bean is not provided by the webapp developer. Instead, it is dynamically created by Struts.
Note that the DynaActionForm class has a set() method that takes a property name, which should be one specified in the form-bean definition, and a value to set that property to.
It is important to recognize that the loginForm and optionsForm beans are used in contrasting ways:
logic:iterate also specifies an id attribute, whose value is used to refer to the individual objects in the collection being iterated over. The body of logic:iterate can then refer to the individual objects using this attribute value, which in this case is option. When this JSP is rendered, the values of the two string objects, "Add Team" and "Add Player", are written to the selection box using the Struts bean:write tag. Note that validation of the form does not occur, since the user does not fill in any input fields. This is assured by setting the validate attribute to false in the showoptions action element.
When the user makes a selection and submits the page (clicking the Do It button), the selected string is sent as the value of the options parameter in the HTTP request (don't confuse the HTML select tag's use of the name "options" with the similar use here by the Struts logic:iterate tag.) Struts then translates the request into the dispatchOptionForm bean and passes control to the dispatchOption action, as specified in the html:form tag's action attribute. The DispatchOptionAction class then forwards to either AddTeam.jsp or AddPlayer.jsp, depending on the option specified in the form bean.
Here is a diagram showing this flow of control:
Pooled Database access is handled by Tomcat as described in the JSP lab exercise.
Here is a diagram showing this flow of control:
And, to put it all together, here is a diagram showing the interaction of all JSPs, form beans, and action objects: